diff options
author | Anselmo Lacerda S. de Melo <anselmo.melo@openbossa.org> | 2009-10-26 16:05:03 -0300 |
---|---|---|
committer | Anselmo Lacerda S. de Melo <anselmo.melo@openbossa.org> | 2009-10-26 16:05:03 -0300 |
commit | 526fd0247320101beeec0af95b27c90789258d4a (patch) | |
tree | 23045afabc6f52f89ab74b88d3b8e0758b784606 | |
parent | ce6fd7f4f07ba0addc1a384043ca62ef7957aa43 (diff) |
Weather: Initial commit
Signed-off-by: Anselmo Lacerda S. de Melo <anselmo.melo@openbossa.org>
95 files changed, 3137 insertions, 0 deletions
diff --git a/weather/.gitignore b/weather/.gitignore new file mode 100644 index 0000000..0e67ed9 --- /dev/null +++ b/weather/.gitignore @@ -0,0 +1,19 @@ +*.o +moc_*.cpp +weather +qrc_*.cpp +Makefile +*~ +weather_*.sis* +weather.loc +weather.rss +weather*.mmp +weather_reg.rss +weather*.pkg +bld.inf +Makefile_*.mk +.cproject +.project +ABLD.BAT +.make.cache +weather.pro.user diff --git a/weather/carroussel.h b/weather/carroussel.h new file mode 100644 index 0000000..3801cd6 --- /dev/null +++ b/weather/carroussel.h @@ -0,0 +1,39 @@ +#ifndef __CARROUSSEL_H__ +#define __CARROUSSEL_H__ + +template<class T> class Carroussel +{ +public: + Carroussel() : m_pos(0) {} + ~Carroussel() { qDeleteAll(m_list); } + int count() const { return m_list.count(); } + int pos() const { return m_pos; } + void move(int offset) { m_pos = getIndex(m_pos + offset); } + int add(T *item); + T *operator[](int aIdx) { return m_list[getIndex(aIdx + m_pos)]; } +private: + int m_pos; + QList<T*> m_list; + int getIndex(int idx); + int getCarrousselIndex(int idx); +}; + +template<class T> int Carroussel<T>::add(T *item) +{ + int idx = m_list.count() - m_pos; + m_list.append(item); + return idx <= m_list.count() / 2 ? idx : idx - m_list.count(); +} + +template<class T> int Carroussel<T>::getIndex(int idx) +{ + if (m_list.count() == 0) + return 0; + idx %= m_list.count(); + return idx >= 0 ? idx : m_list.count() + idx; +} + + + + +#endif /* __CARROUSSEL_H__ */ diff --git a/weather/citycarroussel.cpp b/weather/citycarroussel.cpp new file mode 100644 index 0000000..8aef53a --- /dev/null +++ b/weather/citycarroussel.cpp @@ -0,0 +1,343 @@ +#include "citycarroussel.h" +#include "settings.h" + +#include <QFont> + +struct ForecastEnvironment +{ + QPixmap picture; + QPixmap effect; + QString description; +}; + +struct ForecastBackgroundData +{ + enum Effect + { + Fog, + Haze, + None + }; + const Forecast::ForecastType type; + const char * nightName; + const char* dayName; + const Effect effect; + const char* description; + + static ForecastEnvironment getEnvironment(Forecast::ForecastType forecast, bool night); + +private: + QString picName(bool night) const { return night ? nightName : dayName; } + +}; + +static ForecastBackgroundData BackgroundData[Forecast::UnknownForecast] = { + {Forecast::MostlyCloudy, "bg_night_rain", "bg_day_rain", ForecastBackgroundData::None, "mostly cloudy"}, + {Forecast::Cloudy, "bg_night_rain", "bg_day_rain", ForecastBackgroundData::None, "cloudy"}, + {Forecast::MostlySunny, "bg_night_clear", "bg_day_clear", ForecastBackgroundData::None, "mostly sunny"}, + {Forecast::PartlyCloudy, "bg_night_clear", "bg_day_clear", ForecastBackgroundData::None, "partially cloudy"}, + {Forecast::Sunny, "bg_night_clear", "bg_day_clear", ForecastBackgroundData::None, "sunny"}, + {Forecast::Flurries, "bg_night_rain", "bg_day_rain", ForecastBackgroundData::None, "flurries"}, + {Forecast::Fog, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::Fog, "fog"}, + {Forecast::Haze, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::Haze, "haze"}, + {Forecast::Sand, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::Haze, "sand"}, + {Forecast::Dust, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::Haze, "dust"}, + {Forecast::Icy, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "icy"}, + {Forecast::Sleet, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "sleet"}, + {Forecast::ChanceOfSleet, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "chance of sleet"}, + {Forecast::Snow, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "snow"}, + {Forecast::ChanceOfSnow, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "chance of snow"}, + {Forecast::Mist, "bg_night_rain", "bg_day_rain", ForecastBackgroundData::None, "mist"}, + {Forecast::Rain, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "rain"}, + {Forecast::ChanceOfRain, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "chance of rain"}, + {Forecast::Storm, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "storm"}, + {Forecast::ChanceOfStorm, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "chance of storm"}, + {Forecast::Thunderstorm, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "thunderstorm"}, + {Forecast::ChanceOfThunderstorm, "bg_night_rain", "bg_day_heavyrain", ForecastBackgroundData::None, "chance of thunderstorm"} +}; + +ForecastEnvironment ForecastBackgroundData::getEnvironment(Forecast::ForecastType forecast, + bool night) +{ + ForecastEnvironment result; + for (int i = 0; i < Forecast::UnknownForecast; ++i) { + if (forecast == BackgroundData[i].type) { + result.picture = Settings::getScaledPic(BackgroundData[i].picName(night)); + + const Effect effect = BackgroundData[i].effect; + const QString name = effect == Haze ? "haze" : effect == Fog ? "fog" : QString(); + result.effect = name.isNull() ? QPixmap() : Settings::getScaledPic(name); + + result.description = BackgroundData[i].description; + if (night) + result.description.append(" at night"); + } + } + return result; +} + +// ForecastBackground + +ForecastBackground::ForecastBackground(QGraphicsItem *parent) + : QGraphicsPixmapItem(parent) + , m_forecast(Forecast::UnknownForecast) + , m_night(false) + , m_effect(0) +{ + setShapeMode(QGraphicsPixmapItem::BoundingRectShape); + + m_text = new QGraphicsTextItem(this); + m_text->setPos(Settings::scaleWidth(120.0), Settings::scaleHeight(820.0)); + + QFont font = m_text->font(); + font.setFamily("Nokia sans"); + font.setPixelSize(Settings::scaleHeight(22)); + font.setBold(true); + m_text->setFont(font); + m_text->setDefaultTextColor(QColor("white")); + +} + +void ForecastBackground::setForecast(Forecast::ForecastType forecast, bool night) +{ + if (forecast == m_forecast && night == m_night) + return; + m_forecast = forecast; + m_night = night; + ForecastEnvironment environment = ForecastBackgroundData::getEnvironment(m_forecast, m_night); + setPixmap(environment.picture); + m_text->setPlainText(environment.description); + + if (environment.effect.isNull()) { + delete m_effect; + m_effect = 0; + } + else { + if (!m_effect) { + m_effect = new QGraphicsPixmapItem(this); + m_effect->setZValue(20.0); + m_effect->setPos(0.0, 0.0); + } + m_effect->setPixmap(environment.effect); + } +} + +void ForecastBackground::setReferencePos(qreal pos) +{ + m_pos = pos; + m_displacement = 0; + setPos(m_pos, 0.0); +} + +void ForecastBackground::setDisplacement(qreal displacement) +{ + m_displacement = displacement; + setPos(m_pos + m_displacement, 0.0); +} + +// CityForecastData + +QSharedPointer<ForecastView> CityForecastData::view() +{ + QSharedPointer<ForecastView> result(m_view.toStrongRef()); + if (!result) { + result = QSharedPointer<ForecastView>(ForecastView::createView(forecast(), night())); + m_view = result.toWeakRef(); + } + return result; +} + +// CityCarrousselGesture + +CityCarrousselGesture::CityCarrousselGesture(CityCarroussel &carroussel, QGraphicsItem *parent) + : GestureBox(parent) + , m_carroussel(carroussel) + , m_active(true) + , m_aborted(false) + , m_startPoint(0.0) +{ +} + +void CityCarrousselGesture::gestureMousePress(QPointF pos, bool &startGesture, bool &acceptClick) +{ + Q_UNUSED(pos); + Q_UNUSED(acceptClick); + startGesture = m_active; +} + +void CityCarrousselGesture::gestureStart(QPointF pos) +{ + m_startPoint = pos.x(); + m_aborted = false; +} + +void CityCarrousselGesture::gestureMove(QPointF pos, QPointF movement, QPointF speed) +{ + Q_UNUSED(movement); + Q_UNUSED(speed); + if (!m_aborted) + m_carroussel.setGestureDisplacement(pos.x() - m_startPoint); +} + +void CityCarrousselGesture::gestureEnd(QPointF pos, QPointF speed) +{ + Q_UNUSED(pos); + Q_UNUSED(speed); + if (!m_aborted) + m_carroussel.move(0); + else + m_aborted = false; +} + +// CityCarroussel + + +static const qreal transparencyRef = 58.0 / 480.0; +static const qreal marginRef = 47.0 / 480.0; +static const qreal backgroundPosRef = -(transparencyRef + marginRef); +static const qreal backgroundWidthRef = 635.0 / 480.0; + +CityCarroussel::CityCarroussel(QGraphicsItem *parent) + : QGraphicsItem(parent) + , m_gestureBox(new CityCarrousselGesture(*this, this)) + , m_boundingRect(QPointF(0.0, 0.0), Settings::windowSize()) + , m_backgroundWidth(backgroundWidthRef * m_boundingRect.width()) + , m_backgroundPos(backgroundPosRef * m_boundingRect.width()) + , m_transparencySize(transparencyRef * m_boundingRect.width()) + , m_distance(m_backgroundWidth - m_transparencySize) +{ + m_gestureBox->setRect(boundingRect()); + + m_positions[0] = m_backgroundPos - m_distance; + m_positions[1] = m_backgroundPos; + m_positions[2] = m_backgroundPos + m_distance; + + m_background.add(new ForecastBackground(this)); + m_background.add(new ForecastBackground(this)); + m_background.add(new ForecastBackground(this)); + + updateBackground(-1); + updateBackground(0); + updateBackground(1); +} + +CityCarroussel::~CityCarroussel() +{ +} + +QRectF CityCarroussel::boundingRect () const +{ + return m_boundingRect; +} + +void CityCarroussel::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *widget) +{ + Q_UNUSED(painter); + Q_UNUSED(opt); + Q_UNUSED(widget); +} + +void CityCarroussel::add(CityForecastData *item) +{ + int idx = m_data.add(item); + if (idx < -1 || idx > 1) + return; + if (m_data.count()< 3) { + updateBackground(-1); + updateBackground(0); + updateBackground(1); + } else + updateBackground(idx); + if (idx == 0) + updateMainItem(); +} + +void CityCarroussel::updateMainItem() +{ + m_view = m_data[0]->view(); + m_view->setPos(-m_positions[1], 0.0); + m_view->setZValue(10.0); + m_view->setParentItem(m_background[0]); + m_view->reset(); + + QAbstractAnimation * animation = m_view->getAnimation(); + if (animation) + animation->start(QAbstractAnimation::DeleteWhenStopped); +} + +void CityCarroussel::updateBackground(int idx) +{ + if (m_data.count() == 0) + m_background[idx]->reset(); + else + m_background[idx]->setForecast(m_data[idx]->forecast(), m_data[idx]->night()); + m_background[idx]->setZValue(idx); + m_background[idx]->setReferencePos(m_positions[idx + 1]); +} + +void CityCarroussel::moveEnd(int direction) +{ + m_gestureBox->setActive(true); + if (direction) { + m_data.move(-direction); + m_background.move(-direction); + for (int i = -1; i <= 1; ++i) { + m_background[i]->setReferencePos(m_positions[i + 1]); + m_background[i]->setZValue(i); + } + updateBackground(-direction); + updateMainItem(); + } +} + +void CityCarroussel::setDisplacement(qreal displacement) +{ + m_displacement = displacement; + for (int i = -1; i <= 1; ++i) + m_background[i]->setDisplacement(m_displacement); + if (m_view) + m_view->setElementsDisplacement(m_displacement / m_distance); +} + +void CityCarroussel::setGestureDisplacement(qreal displacement) +{ + if (qAbs(displacement) > boundingRect().width() * 0.5) { + move(displacement < 0 ? -1 : 1); + } + else + setDisplacement(displacement); +} + +void CityCarroussel::move(int direction) +{ + m_gestureBox->setActive(false); + m_gestureBox->abort(); + + QPropertyAnimation *animation = new QPropertyAnimation(this, "displacement"); + + animation->setEndValue(direction * m_distance); + animation->setEasingCurve(QEasingCurve::OutQuart); + animation->setDuration(500); + + switch(direction) { + case -1: + connect(animation, SIGNAL(finished()), this, SLOT(moveLeftEnd())); + break; + case 0: + connect(animation, SIGNAL(finished()), this, SLOT(moveBackEnd())); + break; + case 1: + connect(animation, SIGNAL(finished()), this, SLOT(moveRightEnd())); + break; + } + animation->start(QAbstractAnimation::DeleteWhenStopped); +} + + + + + + + + + diff --git a/weather/citycarroussel.h b/weather/citycarroussel.h new file mode 100644 index 0000000..b6ff095 --- /dev/null +++ b/weather/citycarroussel.h @@ -0,0 +1,121 @@ +#ifndef CITYCARROUSSEL_H +#define CITYCARROUSSEL_H + +#include "forecast.h" +#include "forecastview.h" +#include "carroussel.h" +#include "gesturebox.h" + +#include <QSharedPointer> +#include <QWeakPointer> + +class CityForecastData +{ +public: + CityForecastData() : m_view() {} + virtual Forecast::ForecastType forecast() const = 0; + virtual bool night() const = 0; + + virtual QSharedPointer<ForecastView> view(); + +private: + QWeakPointer<ForecastView> m_view; +}; + +class ForecastBackground : public QGraphicsPixmapItem +{ +public: + ForecastBackground(QGraphicsItem *parent = 0); + Forecast::ForecastType forecast() const { return m_forecast; } + bool night() const { return m_night; } + + void setForecast(Forecast::ForecastType forecast, bool night); + void reset() { setForecast(Forecast::UnknownForecast, false); } + + void setReferencePos(qreal pos); + void setDisplacement(qreal displacement); + +private: + Forecast::ForecastType m_forecast; + bool m_night; + qreal m_pos; + qreal m_displacement; + + QGraphicsTextItem *m_text; + QGraphicsPixmapItem *m_effect; + +}; + +class CityCarroussel; + +class CityCarrousselGesture : public GestureBox +{ +public: + CityCarrousselGesture(CityCarroussel &carroussel, QGraphicsItem *parent = 0); + void setActivate(bool active) { m_active = active; } + void abort() { m_aborted = true; } + +protected: + void gestureMousePress(QPointF pos, bool &startGesture, bool &acceptClick); + void gestureStart(QPointF pos); + void gestureMove(QPointF pos, QPointF movement, QPointF speed); + void gestureEnd(QPointF pos, QPointF speed); + +private: + CityCarroussel &m_carroussel; + bool m_active; + bool m_aborted; + qreal m_startPoint; + +}; + +class CityCarroussel : public QObject, public QGraphicsItem +{ + Q_OBJECT + Q_INTERFACES(QGraphicsItem) + Q_PROPERTY(qreal displacement READ displacement WRITE setDisplacement) +public: + CityCarroussel(QGraphicsItem *parent = 0); + ~CityCarroussel(); + void add(CityForecastData *item); + + QRectF boundingRect () const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +public slots: + void moveLeft() { move(-1); } + void moveRight() { move(1); } + +private: + friend class CityCarrousselGesture; + + Carroussel<CityForecastData> m_data; + Carroussel<ForecastBackground> m_background; + QSharedPointer<ForecastView> m_view; + qreal m_displacement; + CityCarrousselGesture *m_gestureBox; + const QRectF m_boundingRect; + const qreal m_backgroundWidth; + const qreal m_backgroundPos; + const qreal m_transparencySize; + const qreal m_distance; + qreal m_positions[3]; + + void setGestureDisplacement(qreal displacement); + void moveBack() { move(0); } + void move(int direction); + void moveEnd(int direction); + + void updateBackground(int idx); + void updateMainItem(); + + void setDisplacement(qreal displacement); + qreal displacement() const { return m_displacement; } + +private slots: + void moveLeftEnd() { moveEnd(-1); } + void moveRightEnd() { moveEnd(1); } + void moveBackEnd() { moveEnd(0); } +}; + +#endif // CITYCARROUSSEL_H diff --git a/weather/forecast.h b/weather/forecast.h new file mode 100644 index 0000000..a58d8cb --- /dev/null +++ b/weather/forecast.h @@ -0,0 +1,34 @@ +#ifndef FORECAST_H +#define FORECAST_H + +namespace Forecast +{ + enum ForecastType + { + MostlyCloudy = 0, + Cloudy, + MostlySunny, + PartlyCloudy, + Sunny, + Flurries, + Fog, + Haze, + Sand, + Dust, + Icy, + Sleet, + ChanceOfSleet, + Snow, + ChanceOfSnow, + Mist, + Rain, + ChanceOfRain, + Storm, + ChanceOfStorm, + Thunderstorm, + ChanceOfThunderstorm, + UnknownForecast + }; +} + +#endif // FORECAST_H diff --git a/weather/forecasthungitem.cpp b/weather/forecasthungitem.cpp new file mode 100644 index 0000000..b396944 --- /dev/null +++ b/weather/forecasthungitem.cpp @@ -0,0 +1,114 @@ +#include "forecasthungitem.h" +#include "settings.h" + +#include <QPropertyAnimation> + +#define LINE_NAME_SUFFIX "_line" + +typedef struct +{ + const char * const prefix; + const qreal x; + const qreal y; + + qreal scaledX() const { return Settings::scaleWidth(x); } + qreal scaledY() const { return Settings::scaleHeight(y); } + + QPixmap pic() const { return Settings::getScaledPic(name()); } + QPixmap linePic() const { return Settings::getScaledPic(name() + LINE_NAME_SUFFIX); } + +private: + QString name() const { return prefix; } + +} HungObjectData; + +static HungObjectData HungItemsData[ForecastHungItem::TypeCount] = { + {"cloud_1", 160.0, 3.0}, // Cloud1 + {"cloud_2", 131.0, 6.0}, // Cloud2 + {"cloud_3", 102.0, 11.0}, // Cloud3 + {"cloud_rain_1", 160.0, 3.0}, // CloudRain1 + {"cloud_rain_2", 131.0, 6.0}, // CloudRain2 + {"cloud_rain_3", 102.0, 11.0}, // CloudRain3 + {"cloud_storm_1", 160.0, 3.0}, // CloudStorm1 + {"cloud_storm_2", 131.0, 6.0}, // CloudStorm2 + {"cloud_storm_3", 102.0, 11.0}, // CloudStorm3 + {"cloud_tstorm_1", 160.0, 3.0}, // CloudTStorm1 + {"cloud_tstorm_2", 131.0, 6.0}, // CloudTStorm2 + {"sun", 198.0, 125.0}, // Sun + {"cold_sun", 121.5, 65.0}, // ColdSun + {"moon", 97.5, 18.0} // Moon +}; + +// ForecastHungItem + +ForecastHungItem::ForecastHungItem(ItemType type, QGraphicsItem *parent) + : QGraphicsItem(parent) + , m_type(type) + , m_targetPicTop(0) +{ + setFlag(QGraphicsItem::ItemHasNoContents, true); + + HungObjectData &data = HungItemsData[m_type]; + + m_pic = new QGraphicsPixmapItem(data.pic(), this); + m_line = new QGraphicsPixmapItem(data.linePic(), m_pic); + + m_pic->setPos(0.0, 0.0); + + m_line->setPos(data.scaledX(), data.scaledY() - m_line->boundingRect().bottom()); + reset(); +} + +qreal ForecastHungItem::lineLenght() const +{ + return m_targetPicTop + HungItemsData[m_type].scaledY(); +} + +void ForecastHungItem::setLineLenght(qreal lenght) +{ + m_targetPicTop = lenght - HungItemsData[m_type].scaledY(); +} + +void ForecastHungItem::setLinePos(qreal linePos) +{ + setPos(linePos - HungItemsData[m_type].scaledX(), 0.0); +} + +QPointF ForecastHungItem::picPos() const +{ + return QPointF(pos().x(), pos().y() + m_targetPicTop); +} + +void ForecastHungItem::setPicPos(QPointF picPos) +{ + setPos(picPos.x(), 0.0); + m_targetPicTop = picPos.y(); +} + +void ForecastHungItem::reset() +{ + setPicTop(-m_pic->boundingRect().height()); +} + +QRectF ForecastHungItem::boundingRect () const +{ + return QRectF(0.0, 0.0, m_pic->boundingRect().width(), + m_targetPicTop + m_pic->boundingRect().height()); +} + +void ForecastHungItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *widget) +{ + Q_UNUSED(painter); + Q_UNUSED(opt); + Q_UNUSED(widget); +} + +QAbstractAnimation *ForecastHungItem::getAnimation() +{ + QPropertyAnimation *result = new QPropertyAnimation(this, "picTop"); + result->setStartValue(-m_pic->boundingRect().height()); + result->setEndValue(m_targetPicTop); + result->setEasingCurve(QEasingCurve::OutBack); + result->setDuration(500); + return result; +} diff --git a/weather/forecasthungitem.h b/weather/forecasthungitem.h new file mode 100644 index 0000000..21546c7 --- /dev/null +++ b/weather/forecasthungitem.h @@ -0,0 +1,59 @@ +#ifndef FORECASTHUNGITEM_H +#define FORECASTHUNGITEM_H + +#include <QObject> +#include <QGraphicsItem> +#include <QAbstractAnimation> + +class ForecastHungItem : public QObject, public QGraphicsItem +{ + Q_OBJECT + Q_INTERFACES(QGraphicsItem) + Q_PROPERTY(qreal picTop READ picTop WRITE setPicTop) +public: + enum ItemType { + Cloud1 = 0, + Cloud2, + Cloud3, + CloudRain1, + CloudRain2, + CloudRain3, + CloudStorm1, + CloudStorm2, + CloudStorm3, + CloudTStorm1, + CloudTStorm2, + Sun, + ColdSun, + Moon, + TypeCount + }; + + ForecastHungItem(ItemType type, QGraphicsItem *parent = 0); + QAbstractAnimation *getAnimation(); + + qreal lineLenght() const; + void setLineLenght(qreal lenght); + void setLinePos(qreal linePos); + + QPointF picPos() const; + void setPicPos(QPointF pos); + void setPicPos(qreal x, qreal y) { setPicPos(QPointF(x, y)); } + + void reset(); + + QRectF boundingRect () const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +private: + QGraphicsPixmapItem *m_pic; + QGraphicsPixmapItem *m_line; + ItemType m_type; + qreal m_targetPicTop; + + qreal picTop() const { return m_pic->pos().y(); } + void setPicTop(qreal top) { m_pic->setPos(m_pic->pos().x(), top); } + +}; + +#endif // FORECASTHUNGITEM_H diff --git a/weather/forecastrain.cpp b/weather/forecastrain.cpp new file mode 100644 index 0000000..2a941fd --- /dev/null +++ b/weather/forecastrain.cpp @@ -0,0 +1,79 @@ +#include "forecastrain.h" +#include "settings.h" + +typedef struct +{ + const char * const prefix; + QPixmap pic() const { return Settings::getScaledPic(name()); } + +private: + QString name() const { return prefix; } + +} RainItemData; + +static const int RainItemCount = 3; +static RainItemData RainItemArray[RainItemCount] = { + {"rain_01"}, + {"rain_02"}, + {"rain_03"} +}; + +ForecastRain::ForecastRain(RainType type, QGraphicsItem *parent) + : QGraphicsItem(parent) + , m_animation(this, "progress") +{ + for (int i = Light; i <= type; ++i) { + QGraphicsPixmapItem *item = new QGraphicsPixmapItem(RainItemArray[i].pic(), this); + m_items.append(item); + } + m_animation.setStartValue(0.0); + m_animation.setEndValue(qreal(m_items.count() + 1)); + m_animation.setDuration(1000); + m_animation.setLoopCount(-1); +} + +void ForecastRain::start() +{ + if (m_items.count() > 1) { + switch (m_animation.state()) { + case QAbstractAnimation::Stopped: + m_animation.start(); + break; + case QAbstractAnimation::Paused: + m_animation.resume(); + break; + default: + break; + } + } +} + +QRectF ForecastRain::boundingRect () const +{ + return m_items.isEmpty() ? QRectF() : m_items[0]->boundingRect(); +} + +void ForecastRain::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *widget) +{ + Q_UNUSED(painter); + Q_UNUSED(opt); + Q_UNUSED(widget); +} + +void ForecastRain::stop() +{ + if (m_items.count() > 1 && m_animation.state() == QAbstractAnimation::Running) + m_animation.pause(); +} + +void ForecastRain::setProgress(qreal progress) +{ + m_progress = progress; + for (int i = 0; i < m_items.count(); ++i) { + const qreal opacity = progress < i ? 0.0 + : progress < i + 1 ? progress - qreal(i) + : progress < i + 2 ? progress - qreal(i + 1) + : 0.0; + m_items[i]->setOpacity(opacity); + } +} diff --git a/weather/forecastrain.h b/weather/forecastrain.h new file mode 100644 index 0000000..bf168dc --- /dev/null +++ b/weather/forecastrain.h @@ -0,0 +1,43 @@ +#ifndef FORECASTRAIN_H +#define FORECASTRAIN_H + +#include <QObject> +#include <QGraphicsItem> +#include <QPropertyAnimation> +#include <QGraphicsPixmapItem> + +#include <QDebug> + +class ForecastRain : public QObject, public QGraphicsItem +{ + Q_OBJECT + Q_INTERFACES(QGraphicsItem) + Q_PROPERTY(qreal progress READ progress WRITE setProgress) + Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity) +public: + enum RainType + { + Light = 0, + Medium, + Heavy + }; + ForecastRain(RainType type, QGraphicsItem *parent = 0); + + QRectF boundingRect () const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +public slots: + void start(); + void stop(); + void show() { QGraphicsItem::show(); } + +private: + QList<QGraphicsPixmapItem*> m_items; + QPropertyAnimation m_animation; + qreal m_progress; + + void setProgress(qreal progress); + qreal progress() const { return m_progress; } +}; + +#endif // FORECASTRAIN_H diff --git a/weather/forecastsnow.cpp b/weather/forecastsnow.cpp new file mode 100644 index 0000000..65b8378 --- /dev/null +++ b/weather/forecastsnow.cpp @@ -0,0 +1,155 @@ +#include "forecastsnow.h" +#include "settings.h" + +#include <QPainter> + +typedef struct +{ + const char * const prefix; + QPixmap pic() const { return Settings::getScaledPic(name()); } + +private: + QString name() const { return prefix; } + +} SnowFlaketData; + +static const int SnowFlakeCount = 10; +static SnowFlaketData SnowFlakeArray[SnowFlakeCount] = { + {"snow_flake"}, + {"snow_flake_01"}, + {"snow_flake_02"}, + {"snow_flake_03"}, + {"snow_flake_04"}, + {"snow_flake_05"}, + {"snow_flake_06"}, + {"snow_flake_07"}, + {"snow_flake_08"}, + {"snow_flake_09"}, +}; + +static const qreal maxVerticalSpeed = 70.0; +static const qreal minVerticalSpeed = 30.0; + +static const qreal maxHorizontalSpeed = 100.0; +static const qreal minHorizontalSpeed = 20.0; + +static const qreal windSpeed = 30.0; + +static const qreal speedDeviation = 0.15; + +static const int deviation1 = 2; +static const int deviation2 = 31; + +#define RANDOM_FACTOR (qreal(qrand()) / qreal(RAND_MAX)) + +// ForecastSnow + +ForecastSnow::SnowFlake::SnowFlake(int type, const QSizeF &bounds) + : m_pixmap(SnowFlakeArray[type].pic()) + , m_bounds(bounds) +{ + qreal x = minHorizontalSpeed + windSpeed + + RANDOM_FACTOR * (maxHorizontalSpeed - minHorizontalSpeed); + qreal y = minVerticalSpeed + RANDOM_FACTOR * (maxVerticalSpeed - minVerticalSpeed); + m_speed = QPointF(x, y); +} + +static inline bool doDeviation(qreal &factor) +{ + if (qrand() % deviation2 > deviation1) + return false; + factor = 1.0 + ((qrand() % 2) ? speedDeviation : -speedDeviation); + return true; +} + +void ForecastSnow::SnowFlake::timerEvent(int interval_ms) +{ + const qreal interval_s = qreal(interval_ms) / 1000.0; + qreal x = m_pos.x() + m_speed.x() * interval_s; + qreal y = m_pos.y() + m_speed.y() * interval_s; + + y = y >= m_bounds.height() ? -m_pixmap.height() : y; + x = x <= -m_pixmap.width() ? m_bounds.width() + : x >= m_bounds.width() ? -m_pixmap.width() : x; + + m_pos = QPointF(x, y); + + qreal factor; + if (doDeviation(factor)) + m_speed.setY(qMax(qMin(m_speed.y() * factor, maxVerticalSpeed), minVerticalSpeed)); + if (doDeviation(factor)) { + qreal x = m_speed.x() - windSpeed; + x = qMax(qMin(x * factor, maxHorizontalSpeed), minHorizontalSpeed) + windSpeed; + m_speed.setX(x); + } +} + +void ForecastSnow::SnowFlake::paint(QPainter *painter) +{ + painter->drawPixmap(m_pos, m_pixmap); +} + +ForecastSnow::ForecastSnow(int count, const QRectF &bounds, QGraphicsItem *parent) + : m_bounds(bounds) + , m_parent(parent) + , m_opacity(1.0) + , m_visible(false) +{ + qsrand(QTime(0, 0).secsTo(QTime::currentTime()) * qrand()); + for (int i = 0; i < count; ++i) + m_flakes.append(new SnowFlake(qrand() % 10, m_bounds.size())); + updateFLakesPositions(); +} + +void ForecastSnow::updateFLakesPositions() +{ + qsrand(QTime(0, 0).secsTo(QTime::currentTime()) * qrand()); + foreach(SnowFlake *flake, m_flakes) { + + const qreal height = m_bounds.height() - flake->height(); + const qreal width = m_bounds.width() - flake->width(); + + flake->setPos(width *RANDOM_FACTOR, height *RANDOM_FACTOR); + } +} + +void ForecastSnow::paint(QPainter *painter) +{ + if (!m_visible || m_opacity < 0.0001) + return; + + const qreal opacity = painter->opacity(); + painter->setOpacity(m_opacity); + painter->translate(m_bounds.topLeft()); + + foreach(SnowFlake *flake, m_flakes) { + if (flake->isVisible()) + flake->paint(painter); + } + + painter->setOpacity(opacity); + painter->translate(QPointF(-m_bounds.left(), -m_bounds.top())); +} + +void ForecastSnow::start() +{ + m_lastTick = QTime::currentTime(); + m_ticker.start(30, this); +} + +void ForecastSnow::stop() +{ + m_ticker.stop(); +} + +void ForecastSnow::timerEvent(QTimerEvent *event) +{ + Q_UNUSED(event); + QTime now = QTime::currentTime(); + int interval = m_lastTick.msecsTo(now); + m_lastTick = now; + foreach(SnowFlake *flake, m_flakes) + flake->timerEvent(interval); + if (m_parent) + m_parent->update(m_bounds); +} diff --git a/weather/forecastsnow.h b/weather/forecastsnow.h new file mode 100644 index 0000000..d36b2d4 --- /dev/null +++ b/weather/forecastsnow.h @@ -0,0 +1,64 @@ +#ifndef FORECASTSNOW_H +#define FORECASTSNOW_H + +#include <QObject> +#include <QGraphicsItem> +#include <QBasicTimer> +#include <QTime> + +class ForecastSnow : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity) +public: + ForecastSnow(int count, const QRectF &bounds, QGraphicsItem *parent); + + void paint(QPainter *painter); + + qreal opacity() const { return m_opacity; } + void setOpacity(qreal value) { m_opacity = value; } + +public slots: + void start(); + void stop(); + void show() { m_visible = true; } + void hide() { m_visible = false; } + +protected: + void timerEvent(QTimerEvent *event); + +private: + class SnowFlake + { + public: + SnowFlake(int type, const QSizeF &bounds); + void timerEvent(int interval_ms); + qreal width() const { return m_pixmap.width(); } + qreal height() const { return m_pixmap.height(); } + void setPos(qreal x, qreal y) { m_pos = QPointF(x, y); } + + bool isVisible() const { return !m_pixmap.isNull(); } + + inline void paint(QPainter *painter); + + private: + QPixmap m_pixmap; + const QSizeF m_bounds; + QPointF m_speed; + QPointF m_pos; + }; + + const QRectF m_bounds; + QGraphicsItem *m_parent; + QList<SnowFlake*> m_flakes; + QBasicTimer m_ticker; + QTime m_lastTick; + + qreal m_opacity; + qreal m_visible; + + void updateFLakesPositions(); + +}; + +#endif // FORECASTSNOW_H diff --git a/weather/forecaststars.cpp b/weather/forecaststars.cpp new file mode 100644 index 0000000..7f3459d --- /dev/null +++ b/weather/forecaststars.cpp @@ -0,0 +1,161 @@ +#include "forecaststars.h" +#include "settings.h" + +#include <QTime> +#include <QPropertyAnimation> + +typedef struct +{ + const char * const prefix; + const qreal radius; + QPixmap pic() const { return Settings::getScaledPic(name()); } + +private: + QString name() const { return prefix; } + +} StarObjectData; + +static const int StarTypesCount = 3; +static StarObjectData StarObjectsData[StarTypesCount] = { + {"star_01", 0.30000}, + {"star_02", 0.22428}, + {"star_03", 0.16666} +}; + +// ForecastStars + +ForecastStars::Star::Star(int type, QGraphicsItem *parent) + : QGraphicsPixmapItem(StarObjectsData[type].pic(), parent) + , starType(type) +{ + setOpacity(0.0); + hide(); +} + +ForecastStars::ForecastStars(int count, QGraphicsItem *parent) + : QGraphicsItem(parent) + , m_progress(1.0) +{ + setFlag(QGraphicsItem::ItemHasNoContents, true); + qsrand(QTime(0, 0).secsTo(QTime::currentTime()) * qrand()); + for (int i = 0; i < count; ++i) + m_starts.append(new Star(qrand() % 3, this)); +} + +QAbstractAnimation *ForecastStars::getAnimation() +{ + QPropertyAnimation *result = new QPropertyAnimation(this, "progress"); + result->setStartValue(0.0); + result->setEndValue(1.0); + result->setEasingCurve(QEasingCurve::OutBack); + result->setDuration(m_starts.count() * 100); + connect(result, SIGNAL(stateChanged(QAbstractAnimation::State,QAbstractAnimation::State)), + this, SLOT(animationStateChanged(QAbstractAnimation::State,QAbstractAnimation::State))); + return result; +} + +void ForecastStars::animationStateChanged(QAbstractAnimation::State oldState, + QAbstractAnimation::State newState) +{ + if (oldState == QAbstractAnimation::Stopped && newState == QAbstractAnimation::Running) { + foreach (Star *star, m_starts) { + star->setOpacity(0.0); + star->show(); + } + } +} + +void ForecastStars::setRect(QRectF rect) +{ + setPos(rect.topLeft()); + m_boundingRect = rect; + m_boundingRect.moveTo(0.0, 0.0); + updateStarsPositions(); +} + +QRectF ForecastStars::boundingRect () const +{ + return m_boundingRect; +} + +QRectF ForecastStars::rect() const +{ + QRectF result(m_boundingRect); + result.moveTo(pos()); + return result; +} + +void ForecastStars::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *widget) +{ + Q_UNUSED(painter); + Q_UNUSED(opt); + Q_UNUSED(widget); +} + +void ForecastStars::setProgress(qreal progress) +{ + m_progress = progress; + const qreal delta = 1.0 / qreal(m_starts.count()); + + for (int i = 0; i < m_starts.count(); ++i) { + qreal val = progress - i * delta; + m_starts[i]->setOpacity(val < 0.0 ? 0.0 : val > delta ? 1.0 : val / delta); + } +} + +bool ForecastStars::checkColision(const QRectF &rect1, qreal radius1, + const QRectF &rect2, qreal radius2) +{ + QPointF p1(rect1.left() + rect1.width() / 2.0, rect1.top() + rect1.height() / 2.0); + QPointF p2(rect2.left() + rect2.width() / 2.0, rect2.top() + rect2.height() / 2.0); + qreal min = radius1 + radius2; + return qAbs(p1.x() - p2.x()) > min && qAbs(p1.y() - p2.y()) > min; +} + +bool ForecastStars::checkColision(Star *item1, Star *item2) +{ + QRectF r1 = item1->boundingRect(); + r1.moveTo(item1->pos()); + qreal radius1 = item1->boundingRect().width() * StarObjectsData[item1->starType].radius; + + QRectF r2 = item2->boundingRect(); + r2.moveTo(item2->pos()); + qreal radius2 = item2->boundingRect().width() * StarObjectsData[item2->starType].radius; + + return checkColision(r1, radius1, r2, radius2); +} + +bool ForecastStars::checkColision(Star *star, const QList<Star*> &items) +{ + foreach(Star *item, items) { + if (!checkColision(star, item)) + return false; + } + return true; +} + +QPointF ForecastStars::getRandomPos(const QRectF &border) +{ + return QPointF(qreal(qrand()) / qreal(RAND_MAX) * border.width() + border.left(), + qreal(qrand()) / qreal(RAND_MAX) * border.height() + border.top()); +} + +void ForecastStars::updateStarsPositions() +{ + QList<Star*> items; + qsrand(QTime(0, 0).secsTo(QTime::currentTime()) * qrand()); + foreach(Star *star, m_starts) { + const QRectF rect(boundingRect()); + const QRectF starRect(star->boundingRect()); + const QPointF topLeft(rect.left() - starRect.left(), rect.top() - starRect.top()); + const QPointF bottomRight(rect.right() - starRect.right(), + rect.bottom() - starRect.bottom()); + const QRectF border(topLeft, bottomRight); + + int tries = 10; + do + star->setPos(getRandomPos(border)); + while (tries-- && !checkColision(star, items)); + items.append(star); + } +} diff --git a/weather/forecaststars.h b/weather/forecaststars.h new file mode 100644 index 0000000..ec63953 --- /dev/null +++ b/weather/forecaststars.h @@ -0,0 +1,50 @@ +#ifndef FORECASTSTARS_H +#define FORECASTSTARS_H + +#include <QObject> +#include <QGraphicsItem> +#include <QAbstractAnimation> + +class ForecastStars : public QObject, public QGraphicsItem +{ + Q_OBJECT + Q_INTERFACES(QGraphicsItem) + Q_PROPERTY(qreal progress READ progress WRITE setProgress) +public: + ForecastStars(int count, QGraphicsItem *parent = 0); + QAbstractAnimation *getAnimation(); + + QRectF rect() const; + void setRect(QRectF rect); + + QRectF boundingRect () const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + +private: + class Star : public QGraphicsPixmapItem + { + public: + Star(int type, QGraphicsItem *parent); + const int starType; + }; + + qreal m_progress; + QRectF m_boundingRect; + QList<Star*> m_starts; + + void setProgress(qreal progress); + qreal progress() const { return m_progress; } + + inline bool checkColision(const QRectF &rect1, qreal radius1, + const QRectF &rect2, qreal radius2); + inline bool checkColision(Star *item1, Star *item2); + inline bool checkColision(Star *star, const QList<Star*> &items); + inline QPointF getRandomPos(const QRectF &border); + void updateStarsPositions(); + +private slots: + void animationStateChanged(QAbstractAnimation::State oldState, + QAbstractAnimation::State newState); +}; + +#endif // FORECASTSTARS_H diff --git a/weather/forecastview.cpp b/weather/forecastview.cpp new file mode 100644 index 0000000..4b6c455 --- /dev/null +++ b/weather/forecastview.cpp @@ -0,0 +1,687 @@ +#include "forecastview.h" +#include "settings.h" + +#include <QPropertyAnimation> +#include <QParallelAnimationGroup> +#include <QSequentialAnimationGroup> + +#include <QDebug> + +// Variations + +struct VariationData +{ + const qreal x; + const qreal y; +}; + +static const int variationCount = 3; +static const VariationData variationArray[variationCount] = +{ + {35.0, 20.0}, + {25.0, 15.0}, + {15.0, 10.0} +}; + +// Sun positions + +struct SunPosition +{ + const ForecastHungItem::ItemType type; + const qreal linePos; + const qreal picTop; +}; + +static const int sunPositionsArrayCount = 3; +static const SunPosition sunPositionsArray[sunPositionsArrayCount] = +{ + {ForecastHungItem::Sun, 240, 124}, + {ForecastHungItem::ColdSun, 240, 205}, + {ForecastHungItem::Moon, 240, 235} +}; + +class ForecastMostlyCloudyView : public ForecastView +{ +public: + ForecastMostlyCloudyView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::MostlyCloudy, parent) + { + if (night) { + addHungItem(ForecastHungItem::CloudRain1, QPointF(357, 308), 0); + addHungItem(ForecastHungItem::CloudRain2, QPointF(46, 274), 1); + addHungItem(ForecastHungItem::CloudRain2, QPointF(463, 273), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(139, 221), 2); + setMainHangItem(ForecastHungItem::Moon); + } else { + addHungItem(ForecastHungItem::Cloud1, QPointF(357, 308), 0); + addHungItem(ForecastHungItem::Cloud2, QPointF(46, 274), 1); + addHungItem(ForecastHungItem::Cloud2, QPointF(463, 273), 1); + addHungItem(ForecastHungItem::Cloud3, QPointF(139, 221), 2); + setMainHangItem(ForecastHungItem::ColdSun); + } + } +}; + +class ForecastCloudyView : public ForecastView +{ +public: + ForecastCloudyView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::Cloudy, parent) + { + if (night) { + addHungItem(ForecastHungItem::CloudRain1, QPointF(440, 275), 0); + addHungItem(ForecastHungItem::CloudRain1, QPointF(121, 273), 0); + addHungItem(ForecastHungItem::CloudRain2, QPointF(307, 266), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(372, 224), 2); + addHungItem(ForecastHungItem::CloudRain3, QPointF(33, 227), 2); + setMainHangItem(ForecastHungItem::Moon); + } else { + addHungItem(ForecastHungItem::Cloud1, QPointF(440, 275), 0); + addHungItem(ForecastHungItem::Cloud1, QPointF(121, 273), 0); + addHungItem(ForecastHungItem::Cloud2, QPointF(307, 266), 1); + addHungItem(ForecastHungItem::Cloud3, QPointF(372, 224), 2); + addHungItem(ForecastHungItem::Cloud3, QPointF(33, 227), 2); + setMainHangItem(ForecastHungItem::ColdSun); + } + } +}; + +class ForecastMostlySunnyView : public ForecastView +{ +public: + ForecastMostlySunnyView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::MostlySunny, parent) + { + if (night) { + addHungItem(ForecastHungItem::CloudRain2, QPointF(72, 389), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(454, 295), 2); + addHungItem(ForecastHungItem::CloudRain3, QPointF(48, 164), 2); + setMainHangItem(ForecastHungItem::Moon); + addStars(); + } else { + addHungItem(ForecastHungItem::Cloud2, QPointF(72, 389), 1); + addHungItem(ForecastHungItem::Cloud3, QPointF(454, 295), 2); + addHungItem(ForecastHungItem::Cloud3, QPointF(48, 164), 2); + setMainHangItem(ForecastHungItem::Sun); + } + } +}; + +class ForecastPartlyCloudyView : public ForecastView +{ +public: + ForecastPartlyCloudyView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::PartlyCloudy, parent) + { + if (night) { + addHungItem(ForecastHungItem::CloudRain1, QPointF(389, 315), 0); + addHungItem(ForecastHungItem::CloudRain2, QPointF(92, 300), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(451, 258), 2); + setMainHangItem(ForecastHungItem::Moon); + } else { + addHungItem(ForecastHungItem::Cloud1, QPointF(389, 315), 0); + addHungItem(ForecastHungItem::Cloud2, QPointF(92, 300), 1); + addHungItem(ForecastHungItem::Cloud3, QPointF(451, 258), 2); + setMainHangItem(ForecastHungItem::Sun); + } + } +}; + +class ForecastSunnyView : public ForecastView +{ +public: + ForecastSunnyView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::Sunny, parent) + { + if (night) { + setMainHangItem(ForecastHungItem::Moon); + addStars(); + } else { + setMainHangItem(ForecastHungItem::Sun); + } + } +}; + +class ForecastFlurriesView : public ForecastView +{ +public: + ForecastFlurriesView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::Flurries, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudRain1, QPointF(113, 300), 0); + addHungItem(ForecastHungItem::CloudRain1, QPointF(382, 267), 0, true); + addHungItem(ForecastHungItem::CloudRain2, QPointF(72, 243), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(349, 226), 2); + addSnow(10); + } +}; + +class ForecastFogView : public ForecastView +{ +public: + ForecastFogView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::Fog, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudRain2, QPointF(95, 311), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(363, 236), 2); + } +}; + +class ForecastHazeView : public ForecastView +{ + // haze || sand || dust +public: + ForecastHazeView(Forecast::ForecastType type, bool night, QGraphicsItem *parent = 0) + : ForecastView(type, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudRain2, QPointF(98, 311), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(396, 235), 2); + } +}; + +class ForecastIcyView : public ForecastView +{ +public: + ForecastIcyView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::Icy, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudRain1, QPointF(113, 300), 0); + addHungItem(ForecastHungItem::CloudRain1, QPointF(382, 267), 0, true); + addHungItem(ForecastHungItem::CloudRain2, QPointF(72, 243), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(349, 226), 2); + addSnow(10); + } +}; + +class ForecastSleetView : public ForecastView +{ +public: + ForecastSleetView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::Sleet, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudRain1, QPointF(135, 317), 0); + addHungItem(ForecastHungItem::CloudRain2, QPointF(341, 313), 1, true); + addHungItem(ForecastHungItem::CloudRain2, QPointF(72, 276), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(199, 250), 2); + addHungItem(ForecastHungItem::CloudRain3, QPointF(417, 268), 2); + addSnow(10); + addRain(ForecastRain::Light); + } +}; + +class ForecastChanceOfSleetView : public ForecastView +{ +public: + ForecastChanceOfSleetView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::ChanceOfSleet, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudRain1, QPointF(135, 317), 0); + addHungItem(ForecastHungItem::CloudRain2, QPointF(341, 313), 1, true); + addHungItem(ForecastHungItem::CloudRain2, QPointF(72, 276), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(199, 250), 2); + addHungItem(ForecastHungItem::CloudRain3, QPointF(417, 268), 2); + addSnow(10); + addRain(ForecastRain::Light); + } +}; + +class ForecastSnowView : public ForecastView +{ +public: + ForecastSnowView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::Snow, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudRain1, QPointF(46, 325), 0); + addHungItem(ForecastHungItem::CloudRain1, QPointF(359, 302), 0, true); + addHungItem(ForecastHungItem::CloudRain2, QPointF(158, 288), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(73, 267), 2); + addHungItem(ForecastHungItem::CloudRain3, QPointF(401, 273), 2); + addSnow(20); + } +}; + +class ForecastChanceOfSnowView : public ForecastView +{ +public: + ForecastChanceOfSnowView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::ChanceOfSnow, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudRain1, QPointF(46, 325), 0); + addHungItem(ForecastHungItem::CloudRain1, QPointF(359, 302), 0, true); + addHungItem(ForecastHungItem::CloudRain2, QPointF(158, 288), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(73, 267), 2); + addHungItem(ForecastHungItem::CloudRain3, QPointF(401, 273), 2); + addSnow(20); + } +}; + +class ForecastMistView : public ForecastView +{ +public: + ForecastMistView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::Mist, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudRain1, QPointF(52, 312), 0); + addHungItem(ForecastHungItem::CloudRain1, QPointF(437, 255), 0); + addHungItem(ForecastHungItem::CloudRain2, QPointF(246, 311), 1, true); + addHungItem(ForecastHungItem::CloudRain3, QPointF(119, 268), 2); + addHungItem(ForecastHungItem::CloudRain3, QPointF(352, 244), 2); + addRain(ForecastRain::Light); + } +}; + +class ForecastRainView : public ForecastView +{ +public: + ForecastRainView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::Rain, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudRain1, QPointF(60, 317), 0); + addHungItem(ForecastHungItem::CloudRain1, QPointF(308, 287), 0, true); + addHungItem(ForecastHungItem::CloudRain2, QPointF(192, 251), 1); + addHungItem(ForecastHungItem::CloudRain2, QPointF(432, 268), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(355, 235), 2); + addRain(ForecastRain::Medium); + } +}; + +class ForecastChanceOfRainView : public ForecastView +{ +public: + ForecastChanceOfRainView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::ChanceOfRain, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudRain1, QPointF(60, 317), 0); + addHungItem(ForecastHungItem::CloudRain1, QPointF(308, 287), 0, true); + addHungItem(ForecastHungItem::CloudRain2, QPointF(192, 251), 1); + addHungItem(ForecastHungItem::CloudRain2, QPointF(432, 268), 1); + addHungItem(ForecastHungItem::CloudRain3, QPointF(355, 235), 2); + addRain(ForecastRain::Medium); + } +}; + +class ForecastStormView : public ForecastView +{ +public: + ForecastStormView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::Storm, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudStorm1, QPointF(324, 296), 0); + addHungItem(ForecastHungItem::CloudStorm1, QPointF(91, 261), 0, true); + addHungItem(ForecastHungItem::CloudStorm2, QPointF(432, 257), 1); + addHungItem(ForecastHungItem::CloudStorm3, QPointF(92, 210), 2); + addHungItem(ForecastHungItem::CloudStorm3, QPointF(334, 224), 2); + addRain(ForecastRain::Heavy); + } +}; + +class ForecastChanceOfStormView : public ForecastView +{ +public: + ForecastChanceOfStormView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::ChanceOfStorm, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudStorm1, QPointF(324, 296), 0); + addHungItem(ForecastHungItem::CloudStorm1, QPointF(91, 261), 0, true); + addHungItem(ForecastHungItem::CloudStorm2, QPointF(432, 257), 1); + addHungItem(ForecastHungItem::CloudStorm3, QPointF(92, 210), 2); + addHungItem(ForecastHungItem::CloudStorm3, QPointF(334, 224), 2); + addRain(ForecastRain::Heavy); + } +}; + +class ForecastThunderstormView : public ForecastView +{ +public: + ForecastThunderstormView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::Thunderstorm, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudTStorm1, QPointF(371, 303), 0); + addHungItem(ForecastHungItem::CloudStorm1, QPointF(110, 283), 0, true); + addHungItem(ForecastHungItem::CloudTStorm2, QPointF(207, 272), 1); + addHungItem(ForecastHungItem::CloudStorm2, QPointF(367, 248), 1); + addHungItem(ForecastHungItem::CloudStorm3, QPointF(111, 223), 2); + addRain(ForecastRain::Heavy); + } +}; + +class ForecastChanceThunderstormView : public ForecastView +{ +public: + ForecastChanceThunderstormView(bool night, QGraphicsItem *parent = 0) + : ForecastView(Forecast::ChanceOfThunderstorm, parent) + { + setMainHangItem(night ? ForecastHungItem::Moon : ForecastHungItem::ColdSun); + addHungItem(ForecastHungItem::CloudTStorm1, QPointF(371, 303), 0); + addHungItem(ForecastHungItem::CloudStorm1, QPointF(110, 283), 0, true); + addHungItem(ForecastHungItem::CloudTStorm2, QPointF(207, 272), 1); + addHungItem(ForecastHungItem::CloudStorm2, QPointF(367, 248), 1); + addHungItem(ForecastHungItem::CloudStorm3, QPointF(111, 223), 2); + addRain(ForecastRain::Heavy); + } +}; + +static const qreal minHungItemsZ = -1.0; +static const qreal maxHungItemsZ = 0.0; +static const qreal sunZ = (minHungItemsZ + maxHungItemsZ) / 2.0 + 0.01; +static const qreal starsZ = -2.0; + +static const qreal radius = (maxHungItemsZ - minHungItemsZ) * 1; +static const qreal maxDisplacementFactor = 1.5; + +// HungItemsManager + +static QAbstractAnimation *addPause(QAbstractAnimation *animation, int pause_ms) +{ + if (!animation || pause_ms <= 0) + return animation; + QSequentialAnimationGroup *result = new QSequentialAnimationGroup(); + result->addPause(pause_ms); + result->addAnimation(animation); + return result; +} + +void HungItemsManager::reset() +{ + for (int i = 0; i < m_items.count(); ++i) { + m_items[i]->reset(); + m_items[i]->setPos(m_positions[i], 0.0); + } + if (m_sun) { + m_sun->reset(); + m_sun->setPos(m_sunPos, 0.0); + } +} + +QAbstractAnimation *HungItemsManager::getAnimation() +{ + QList<QAbstractAnimation*> list; + const qreal diff = (m_maxZ - m_minZ) / qreal(m_items.count()); + + for (int i = 0; i < m_items.count(); ++i) { + m_items[i]->setZValue(m_maxZ - i * diff); + QAbstractAnimation *animation = m_items[i]->getAnimation(); + if (animation) + list.append(animation); + } + + QAbstractAnimation *clouds = 0; + + switch (list.count()) { + case 0: break; + case 1: + clouds = list[0]; + break; + default: { + QParallelAnimationGroup *animation = new QParallelAnimationGroup(); + for (int i = 0; i < list.count(); ++i) + animation->addAnimation(addPause(list[i], i * 200)); + clouds = animation; + } + } + + QAbstractAnimation *sun = m_sun ? m_sun->getAnimation() : 0; + + if (clouds && m_sun) { + QSequentialAnimationGroup *result = new QSequentialAnimationGroup(); + result->addAnimation(clouds); + result->addAnimation(sun); + return result; + } + return clouds ? clouds : sun; +} + +void HungItemsManager::addItem(ForecastHungItem *item) +{ + m_items.append(item); + m_positions.append(item->pos().x()); +} + +void HungItemsManager::setSun(ForecastHungItem *sun) +{ + m_sun = sun; + m_sunPos = sun->pos().x(); +} + +void HungItemsManager::doSetDisplacement(ForecastHungItem *item, qreal max, qreal pos) +{ + const qreal itemRadius = radius + item->zValue(); + const qreal itemDisplacement = (itemRadius / radius) * max * m_displacement; + item->setPos(pos + itemDisplacement, 0.0); +} + +void HungItemsManager::setElementsDisplacement(qreal displacement) +{ + const qreal max = maxDisplacementFactor * Settings::windowSize().width(); + m_displacement = qMin(qMax(displacement, qreal(-1.0)), qreal(1.0)); + for (int i = 0; i < m_items.count(); ++i) + doSetDisplacement(m_items[i], max, m_positions[i]); + if (m_sun) + doSetDisplacement(m_sun, max, m_sunPos); +} + +// ForecastView + +void ForecastView::setElementsDisplacement(qreal displacement) +{ + m_hungManager.setElementsDisplacement(displacement); +} + +ForecastView *ForecastView::createView(Forecast::ForecastType type, bool night, QGraphicsItem *parent) +{ + switch (type) { + case Forecast::MostlyCloudy : return new ForecastMostlyCloudyView(night, parent); + case Forecast::Cloudy : return new ForecastCloudyView(night, parent); + case Forecast::MostlySunny : return new ForecastMostlySunnyView(night, parent); + case Forecast::PartlyCloudy : return new ForecastPartlyCloudyView(night, parent); + case Forecast::Sunny : return new ForecastSunnyView(night, parent); + case Forecast::Flurries : return new ForecastFlurriesView(night, parent); + case Forecast::Fog : return new ForecastFogView(night, parent); + case Forecast::Haze : return new ForecastHazeView(Forecast::Haze, night, parent); + case Forecast::Sand : return new ForecastHazeView(Forecast::Sand, night, parent); + case Forecast::Dust : return new ForecastHazeView(Forecast::Dust, night, parent); + case Forecast::Icy : return new ForecastIcyView(night, parent); + case Forecast::Sleet : return new ForecastSleetView(night, parent); + case Forecast::ChanceOfSleet : return new ForecastChanceOfSleetView(night, parent); + case Forecast::Snow : return new ForecastSnowView(night, parent); + case Forecast::ChanceOfSnow : return new ForecastChanceOfSnowView(night, parent); + case Forecast::Mist : return new ForecastMistView(night, parent); + case Forecast::Rain : return new ForecastRainView(night, parent); + case Forecast::ChanceOfRain : return new ForecastChanceOfRainView(night, parent); + case Forecast::Storm : return new ForecastStormView(night, parent); + case Forecast::ChanceOfStorm : return new ForecastChanceOfStormView(night, parent); + case Forecast::Thunderstorm : return new ForecastThunderstormView(night, parent); + case Forecast::ChanceOfThunderstorm : return new ForecastChanceThunderstormView(night, parent); + default : return 0; + } + +} + +ForecastView::ForecastView(Forecast::ForecastType type, bool night, QGraphicsItem *parent) + : QGraphicsItem(parent) + , m_type(type) + , m_night(night) + , m_boundingRect(QPointF(0.0, 0.0), Settings::windowSize()) + , m_hungManager(minHungItemsZ, maxHungItemsZ) + , m_stars(0) + , m_reference(0) + , m_rain(0) + , m_snow(0) +{ +} + +ForecastView::~ForecastView() +{ + delete m_snow; +} + +QRectF ForecastView::boundingRect () const +{ + return m_boundingRect; +} + +void ForecastView::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt, QWidget *widget) +{ + Q_UNUSED(opt); + Q_UNUSED(widget); + if (m_snow) + m_snow->paint(painter); +} + +static const qreal cloudAdjustment = 20.0; + +void ForecastView::addHungItem(ForecastHungItem::ItemType type, const QPointF &itemPos, + int deviation, bool reference) +{ + const bool validDev = deviation >= 0 && deviation < variationCount; + + qreal devX = validDev ? variationArray[deviation].x : 0.0; + qreal devY = validDev ? variationArray[deviation].y : 0.0; + + devX *= 1.0 - qreal(qrand()) / qreal(RAND_MAX >> 1); + devY *= 1.0 - qreal(qrand()) / qreal(RAND_MAX >> 1); + + ForecastHungItem *item = new ForecastHungItem(type, this); + item->setLinePos(Settings::scaleWidth(itemPos.x() + devX - cloudAdjustment)); + item->setPicPos(item->pos().x(), Settings::scaleHeight(itemPos.y() + devY)); + + if (reference) + m_reference = item; + + m_hungManager.addItem(item); +} + +void ForecastView::reset() +{ + m_hungManager.reset(); + if (m_rain) { + m_rain->stop(); + m_rain->hide(); + } + if (m_snow) { + m_snow->stop(); + m_snow->hide(); + } +} + +void ForecastView::addStars() +{ + if (!m_stars) { + m_stars = new ForecastStars(8, this); + QRectF rect = m_boundingRect; + rect.setHeight(Settings::scaleHeight(522.0)); + m_stars->setRect(rect); + m_stars->setZValue(starsZ); + } +} + +QRectF ForecastView::getEffectRect() +{ + QRectF result = m_boundingRect; + if (m_reference) { + QRectF ref(m_reference->boundingRect()); + result.setTop(ref.bottom()); + result.setHeight(m_boundingRect.height() - ref.bottom()); + } + return result; +} + +template<class T> QAbstractAnimation *ForecastView::createEffectAnimation(T *effect) +{ + effect->setOpacity(0.0); + EffectAnimation *result = new EffectAnimation(); + result->setTargetObject(effect); + result->setPropertyName("opacity"); + result->setStartValue(0.0); + result->setEndValue(1.0); + result->setDuration(200); + result->setEasingCurve(QEasingCurve::InQuart); + connect(result, SIGNAL(started()), effect, SLOT(show())); + connect(result, SIGNAL(finished()), effect, SLOT(start())); + return result; +} + +void ForecastView::addRain(ForecastRain::RainType type) +{ + if (!m_rain) { + m_rain = new ForecastRain(type, this); + m_rain->setPos(getEffectRect().topLeft()); + m_rain->hide(); + if (m_reference) + m_rain->setZValue(m_reference->zValue()); + } +} + +void ForecastView::addSnow(int count) +{ + if (!m_snow) { + m_snow = new ForecastSnow(count, getEffectRect(), this); + m_snow->hide(); + } +} + +void ForecastView::setMainHangItem(ForecastHungItem::ItemType type) +{ + if (!m_hungManager.sun()) { + for (int i = 0; i < sunPositionsArrayCount; ++i) { + if (sunPositionsArray[i].type == type ){ + ForecastHungItem *sun = new ForecastHungItem(type, this); + sun->setPicPos(0.0, Settings::scaleHeight(sunPositionsArray[i].picTop)); + sun->setLinePos(Settings::scaleWidth(sunPositionsArray[i].linePos)); + sun->setZValue(sunZ); + m_hungManager.setSun(sun); + break; + } + } + } +} + +QAbstractAnimation *ForecastView::getAnimation() +{ + QList<QAbstractAnimation*> list; + + QAbstractAnimation *animation = m_hungManager.getAnimation(); + if (animation) + list.append(animation); + + animation = m_stars ? m_stars->getAnimation() : 0; + if (animation) + list.append(animation); + + animation = m_rain ? createEffectAnimation(m_rain) : 0; + if (animation) + list.append(animation); + + animation = m_snow ? createEffectAnimation(m_snow) : 0; + if (animation) + list.append(animation); + + switch (list.count()) { + case 0: return 0; + case 1: return list[0]; + default: { + QSequentialAnimationGroup *result = new QSequentialAnimationGroup(); + foreach (QAbstractAnimation *a, list) + result->addAnimation(a); + return result; + } + } +} + + + + diff --git a/weather/forecastview.h b/weather/forecastview.h new file mode 100644 index 0000000..aca7eb6 --- /dev/null +++ b/weather/forecastview.h @@ -0,0 +1,102 @@ +#ifndef FORECASTVIEW_H +#define FORECASTVIEW_H + +#include <QObject> +#include <QGraphicsItem> +#include <QAbstractAnimation> + +#include "forecasthungitem.h" +#include "forecastsnow.h" +#include "forecastrain.h" +#include "forecaststars.h" +#include "forecast.h" + +class HungItemsManager +{ +public: + HungItemsManager(qreal minZ, qreal maxZ) + : m_minZ(minZ) + , m_maxZ(maxZ) + , m_displacement(0.0) + , m_sun(0) + , m_sunPos(0) {} + void setSun(ForecastHungItem *sun); + ForecastHungItem *sun() { return m_sun; } + void addItem(ForecastHungItem *item); + QAbstractAnimation *getAnimation(); + void reset(); + void setElementsDisplacement(qreal displacement); +private: + const qreal m_minZ; + const qreal m_maxZ; + qreal m_displacement; + ForecastHungItem *m_sun; + qreal m_sunPos; + QList<ForecastHungItem*> m_items; + QList<qreal> m_positions; + + void doSetDisplacement(ForecastHungItem *item, qreal max, qreal pos); +}; + +class EffectAnimation : public QPropertyAnimation +{ + Q_OBJECT +public: +signals: + void started(); +protected: + void updateState(QAbstractAnimation::State oldState, QAbstractAnimation::State newState) + { + if (oldState == Stopped && newState == Running) + emit started(); + } + +private: +}; + +class ForecastView : public QObject, public QGraphicsItem +{ + Q_OBJECT + Q_INTERFACES(QGraphicsItem) +public: + ~ForecastView(); + QRectF boundingRect () const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + Forecast::ForecastType viewType() const { return m_type; } + bool night() const { return m_night; } + + void setElementsDisplacement(qreal displacement); + + void reset(); + QAbstractAnimation *getAnimation(); + + static ForecastView *createView(Forecast::ForecastType type, bool night, QGraphicsItem *parent = 0); + + +protected: + ForecastView(Forecast::ForecastType type, bool night, QGraphicsItem *parent = 0); + + void addHungItem(ForecastHungItem::ItemType type, const QPointF &itemPos, + int deviation, bool reference = false); + void setMainHangItem(ForecastHungItem::ItemType); + void addStars(); + + void addSnow(int count); + void addRain(ForecastRain::RainType); + +private: + const Forecast::ForecastType m_type; + const bool m_night; + const QRectF m_boundingRect; + HungItemsManager m_hungManager; + ForecastStars *m_stars; + ForecastHungItem *m_reference; + ForecastRain *m_rain; + ForecastSnow *m_snow; + + QRectF getEffectRect(); + template<class T> QAbstractAnimation *createEffectAnimation(T *effect); + +}; + +#endif // FORECASTVIEW_H diff --git a/weather/gesturebox.cpp b/weather/gesturebox.cpp new file mode 100644 index 0000000..e1d4e22 --- /dev/null +++ b/weather/gesturebox.cpp @@ -0,0 +1,361 @@ +#include "gesturebox.h" + +#include <QApplication> +#include <QGraphicsView> +#include <QMouseEvent> +#include <QDebug> +#include <QPointer> +#include <QTime> + +#include "gesturebox_p.h" + +// GestureData + +#ifdef Q_OS_SYMBIAN +static const int move_threshold = 20; +#else +static const int move_threshold = 5; +#endif + +GestureData::GestureData(QPoint pos, const QList<GestureBox*> &boxes, + QGraphicsView *view, QList<QEvent*> &ignoreList, bool sendClickEvents) + : m_state(Pressed) + , m_view(view) + , m_pressPos(pos) + , m_scenePressPos(m_view->mapToScene(m_pressPos)) + , m_boxes(boxes) + , m_ignoreList(ignoreList) + , m_time(QTime::currentTime()) + , m_currentScenePos(m_scenePressPos) + , m_speed(0.0, 0.0) + , m_sendClickEvents(sendClickEvents) +{ +} + +void GestureData::sendClick() +{ + if (m_sendClickEvents) { + QMouseEvent *press = new QMouseEvent(QEvent::MouseButtonPress, + m_pressPos, Qt::LeftButton, + Qt::LeftButton, Qt::NoModifier); + QMouseEvent *release = new QMouseEvent(QEvent::MouseButtonRelease, + m_pressPos, Qt::LeftButton, + Qt::LeftButton, Qt::NoModifier); + m_ignoreList << press; + m_ignoreList << release; + QApplication::postEvent(m_view->viewport(), press); + QApplication::postEvent(m_view->viewport(), release); + } +} + +void GestureData::release(QPoint pos) +{ + Q_UNUSED(pos); + switch (m_state) { + case Pressed: + sendClick(); + break; + case Moving: + foreach(GestureBox *box, m_boxes) + box->gestureEnd(box->mapFromScene(m_currentScenePos), m_speed); + break; + default: + break; + } + m_state = Ended; + deleteLater(); +} + +void GestureData::move(QPoint pos) +{ + if (m_state == Pressed && + abs(pos.x() - m_pressPos.x()) < move_threshold && + abs(pos.y() - m_pressPos.y()) < move_threshold) { + return; + } + QTime time(QTime::currentTime()); + QPointF scenePos = m_view->mapToScene(pos); + QPointF move = scenePos - m_currentScenePos; + qreal secs = (qreal)(m_time.msecsTo(time)) / 1000; + m_currentScenePos = scenePos; + m_speed = QPointF(move.x() / secs, move.y() / secs); + m_time = time; + + switch (m_state) { + case Pressed: + foreach(GestureBox *box, m_boxes) { + box->gestureStart(box->mapFromScene(m_scenePressPos)); + box->gestureMove(box->mapFromScene(m_currentScenePos), move, m_speed); + } + m_state = Moving; + break; + case Moving: + foreach(GestureBox *box, m_boxes) + box->gestureMove(box->mapFromScene(m_currentScenePos), move, m_speed); + break; + default: + break; + } +} + +// ViewData + +ViewData::~ViewData() +{ + if (m_gesture) + m_gesture->deleteLater(); +} + +bool ViewData::ignoreEvent(QEvent *event) +{ + return m_ignored.removeAll(event); +} + +bool ViewData::startGesture(GestureBox *box, QPointF scenePos, bool &sendClick) +{ + bool result = true; + bool click = true; + box->gestureMousePress(box->mapFromScene(scenePos), result, click); + if (result && !click) + sendClick = false; + return result; +} + +bool ViewData::press(QPoint pos) +{ + if (m_gesture && !m_gesture->ended()) { + qWarning() << "ERROR: unexpected mouse press during gesture."; + return false; + } + + if (!m_view || !m_view->scene()) + return false; + + QList<GestureBox*> boxes; + bool sendClick = true; + QPointF scenePos = m_view->mapToScene(pos); + + QList<QGraphicsItem*> itemList = m_view->scene()->items(scenePos, + Qt::IntersectsItemBoundingRect, + Qt::AscendingOrder); + + foreach(QGraphicsItem *item, itemList) { + GestureBox *box = dynamic_cast<GestureBox*>(item); + if (box && startGesture(box, scenePos, sendClick)) + boxes.append(box); + } + + if (boxes.isEmpty()) + return false; + + m_gesture = new GestureData(pos, boxes, m_view, m_ignored, sendClick); + return true; + +} + +bool ViewData::release(QPoint pos) +{ + if (!m_gesture || m_gesture->ended()) + return false; + + m_gesture->release(pos); + return true; +} + +bool ViewData::move(QPoint pos) +{ + if (!m_gesture || m_gesture->ended()) + return false; + + m_gesture->move(pos); + return true; +} + +QList<GestureBox*> ViewData::getBoxList(QPoint pos) { + QList<GestureBox*> result; + if (m_view->scene()) { + QPointF scenePos = m_view->mapToScene(pos); + QGraphicsItem *item = m_view->scene()->itemAt(scenePos); + while (item) { + GestureBox *box = dynamic_cast<GestureBox*>(item); + if (box && box->boundingRect().contains(box->mapFromScene(scenePos))) + result.append(box); + item = item->parentItem(); + } + } + return result; +} + +// GestureObserver + +GestureObserver *GestureObserver::instance() +{ + static GestureObserver *obj = new GestureObserver(); + return obj; +} + +void GestureObserver::addBox(GestureBox *box) +{ + if (box->scene()) { + foreach(QGraphicsView *view, box->scene()->views()) { + ViewData *data = getViewData(view); + if (data->m_boxes.indexOf(box) < 0) { + data->m_boxes.append(box); + m_boxes.insertMulti(box, data); + } + } + } +} + +void GestureObserver::removeBox(GestureBox *box) +{ + QList<ViewData*> dataList = m_boxes.values(box); + foreach(ViewData* data, dataList) { + data->m_boxes.removeAll(box); + if (data->m_boxes.count() == 0) { + m_views.remove(data->view()->viewport()); + data->view()->viewport()->removeEventFilter(this); + delete data; + } + } + m_boxes.remove(box); +} + + +ViewData *GestureObserver::getViewData(QGraphicsView *view) +{ + if (m_views.contains(view->viewport())) + return m_views.value(view->viewport()); + ViewData *data = new ViewData(view); + view->viewport()->installEventFilter(this); + connect(view->viewport(), SIGNAL(destroyed()), this, SLOT(viewDestroyed())); + m_views.insert(view->viewport(), data); + return data; +} + +void GestureObserver::viewDestroyed() +{ + if (!sender()->isWidgetType()) + return; + QWidget *viewport = qobject_cast<QWidget*>(sender()); + if (viewport || m_views.contains(viewport)) { + ViewData *data = m_views.take(viewport); + if (data) { + foreach (GestureBox *box, data->m_boxes) { + QList<ViewData*> boxes = m_boxes.values(box); + m_boxes.remove(box); + + foreach(ViewData *viewData, boxes) { + if (viewData->widget() != viewport) + m_boxes.insertMulti(box, viewData); + } + } + delete data; + } + } + +} + +bool GestureObserver::eventFilter(QObject *object, QEvent *event) +{ + if (!object->isWidgetType()) + return false; + + QEvent::Type type = event->type(); + if (type != QEvent::MouseButtonPress && type != QEvent::MouseButtonRelease && + type != QEvent::MouseMove) + return false; + + QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(event); + if (!mouseEvent || mouseEvent->modifiers() != Qt::NoModifier) + return false; + + QWidget *view = dynamic_cast<QWidget*>(object); + if (!view || !m_views.contains(view)) + return false; + + ViewData *data = m_views[view]; + if (!data || data->ignoreEvent(event)) + return false; + + bool consumed = false; + + switch (mouseEvent->type()) { + case QEvent::MouseButtonPress: + consumed = mouseEvent->buttons() == Qt::LeftButton && data->press(mouseEvent->pos()); + break; + case QEvent::MouseButtonRelease: + consumed = data->release(mouseEvent->pos()); + break; + case QEvent::MouseMove: + consumed = data->move(mouseEvent->pos()); + break; + default: + break; + } + return consumed; +} + +// GestureBox + +GestureBox::GestureBox(QGraphicsItem *parent) + : QGraphicsItem(parent) +{ + GestureObserver::instance()->addBox(this); +} + +GestureBox::~GestureBox() +{ + GestureObserver::instance()->removeBox(this); +} + +QRectF GestureBox::rect() const +{ + QRectF result(m_boundingRect); + result.moveTo(pos()); + return result; +} + +void GestureBox::setRect(QRectF value) +{ + setPos(value.topLeft()); + value.moveTo(0.0, 0.0); + if (value != m_boundingRect) { + prepareGeometryChange(); + m_boundingRect = value; + update(); + } +} + +void GestureBox::setRect(qreal x, qreal y, qreal width, qreal height) +{ + setRect(QRectF(x, y, width, height)); +} + +QRectF GestureBox::boundingRect() const +{ + return m_boundingRect; +} + +void GestureBox::paint(QPainter *painter, + const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(painter); + Q_UNUSED(option); + Q_UNUSED(widget); +} + +QVariant GestureBox::itemChange(GraphicsItemChange change, const QVariant &value) +{ + switch (change) { + case QGraphicsItem::ItemSceneHasChanged: + case QGraphicsItem::ItemParentHasChanged: + GestureObserver::instance()->addBox(this); + break; + default: + break; + } + return value; +} + + diff --git a/weather/gesturebox.h b/weather/gesturebox.h new file mode 100644 index 0000000..302f65c --- /dev/null +++ b/weather/gesturebox.h @@ -0,0 +1,33 @@ +#ifndef GESTUREBOX_H +#define GESTUREBOX_H + +#include <QGraphicsItem> + +class GestureBox : public QGraphicsItem +{ +public: + GestureBox(QGraphicsItem *parent = 0); + ~GestureBox(); + + QRectF rect() const; + void setRect(QRectF); + void setRect(qreal, qreal, qreal, qreal); + QRectF boundingRect() const; + +protected: + virtual void gestureMousePress(QPointF pos, bool &startGesture, bool &acceptClick) = 0; + virtual void gestureStart(QPointF pos) = 0; + virtual void gestureMove(QPointF pos, QPointF movement, QPointF speed) = 0; + virtual void gestureEnd(QPointF pos, QPointF speed) = 0; + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0); + QVariant itemChange(GraphicsItemChange change, const QVariant &value); + +private: + friend class GestureData; + friend class ViewData; + QRectF m_boundingRect; + +}; + +#endif // GESTUREBOX_H diff --git a/weather/gesturebox_p.h b/weather/gesturebox_p.h new file mode 100644 index 0000000..f4f8452 --- /dev/null +++ b/weather/gesturebox_p.h @@ -0,0 +1,89 @@ +#ifndef GESTUREBOX_P_H +#define GESTUREBOX_P_H + +#include <QObject> +#include <QPointer> +#include <QTime> +#include <QPoint> +#include <QPointF> +#include <QGraphicsView> + +#include "gesturebox.h" + +class GestureData : public QObject +{ +public: + inline GestureData(QPoint pos, const QList<GestureBox*> &boxes, QGraphicsView *view, + QList<QEvent*> &ignoreList, bool sendClickEvents); + + inline void release(QPoint pos); + inline void move(QPoint pos); + inline bool ended() const { return m_state == Ended; } + +private: + enum State {Pressed, Moving, Ended}; + State m_state; + QGraphicsView * const m_view; + const QPoint m_pressPos; + const QPointF m_scenePressPos; + const QList<GestureBox*> m_boxes; + QList<QEvent*> &m_ignoreList; + QTime m_time; + QPointF m_currentScenePos; + QPointF m_speed; + bool m_sendClickEvents; + + void sendClick(); +}; + +class ViewData +{ +public: + ViewData(QGraphicsView *view) : m_view(view), m_gesture(0), m_widget(view->viewport()) {} + inline ~ViewData(); + + inline bool press(QPoint pos); + inline bool release(QPoint pos); + inline bool move(QPoint pos); + + QGraphicsView *view() { return m_view; } + QWidget *widget() { return m_widget; } + inline bool ignoreEvent(QEvent *event); + + QList<GestureBox*> m_boxes; + +private: + QGraphicsView *const m_view; + QPointer<GestureData> m_gesture; + QList<QEvent*> m_ignored; + QWidget * const m_widget; + + inline QList<GestureBox*> getBoxList(QPoint pos); + inline bool startGesture(GestureBox *box, QPointF scenePos, bool &sendClick); +}; + +class GestureObserver : public QObject +{ + Q_OBJECT +public: + static inline GestureObserver *instance(); + inline void addBox(GestureBox *box); + inline void removeBox(GestureBox *box); + +protected: + bool eventFilter(QObject *object, QEvent *event); + +private: + QHash<QWidget*, ViewData*> m_views; + QHash<GestureBox*, ViewData*> m_boxes; + + GestureObserver() {} + ~GestureObserver() {} + ViewData *getViewData(QGraphicsView *view); + +private slots: + void viewDestroyed(); + +}; + +#endif // GESTUREBOX_P_H diff --git a/weather/images/icon.svg b/weather/images/icon.svg new file mode 100644 index 0000000..c3a8ff4 --- /dev/null +++ b/weather/images/icon.svg @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 13.0.0, SVG Export Plug-In --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ + <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/"> +]> +<svg version="1.1" + xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" + x="0px" y="0px" width="64px" height="64px" viewBox="-1 0 64 64" enable-background="new -1 0 64 64" xml:space="preserve"> +<defs> +</defs> +<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="302.3994" y1="-325.333" x2="302.3993" y2="-387.3755" gradientTransform="matrix(1 0 0 -1 -265.5 -326)"> + <stop offset="0" style="stop-color:#0C527D"/> + <stop offset="1" style="stop-color:#6BA3C6"/> +</linearGradient> +<path fill="url(#SVGID_1_)" d="M59.4,2.9c2.3,0,4.1,1.8,4.1,4.1v45c0,2.3-1.8,4.1-4.1,4.1h-45c-2.3,0-4.1-1.8-4.1-4.1V7 + c0-2.3,1.8-4.1,4.1-4.1H59.4z"/> +<line fill="none" x1="10.2" y1="33.8" x2="28.4" y2="2.9"/> +<line fill="none" x1="22.5" y1="56.2" x2="53.6" y2="3.1"/> +<line fill="none" x1="24.7" y1="56.2" x2="55.8" y2="3.1"/> +<line fill="none" x1="29.4" y1="56.2" x2="60.6" y2="3.1"/> +<line opacity="0.31" fill="none" stroke="#FFFFFF" stroke-width="0.05" enable-background="new " x1="18.6" y1="56.1" x2="47.3" y2="2.9"/> +<line opacity="0.5" fill="none" stroke="#FFFFFF" stroke-width="0.05" enable-background="new " x1="36" y1="56.1" x2="63.6" y2="6.1"/> +<line opacity="0.31" fill="none" stroke="#FFFFFF" stroke-width="0.05" enable-background="new " x1="10.2" y1="48" x2="34.2" y2="2.9"/> +<line opacity="0.31" fill="none" stroke="#FFFFFF" stroke-width="0.05" enable-background="new " x1="10.2" y1="16.6" x2="17.2" y2="2.9"/> +<line fill="none" x1="10.2" y1="51.8" x2="37.8" y2="3"/> +<line opacity="0.31" fill="none" stroke="#FFFFFF" stroke-width="0.25" enable-background="new " x1="15.5" y1="56.1" x2="44.3" y2="2.8"/> +<line opacity="0.5" fill="none" stroke="#FFFFFF" stroke-width="0.25" enable-background="new " x1="32.1" y1="56.2" x2="60.1" y2="2.9"/> +<line opacity="0.31" fill="none" stroke="#FFFFFF" stroke-width="0.25" enable-background="new " x1="10" y1="43.7" x2="32.1" y2="2.8"/> +<line opacity="0.31" fill="none" stroke="#FFFFFF" stroke-width="0.25" enable-background="new " x1="10.1" y1="20.7" x2="19.5" y2="2.8"/> +<line fill="none" x1="10" y1="49.9" x2="35.5" y2="2.9"/> +<path fill="none" d="M59.3,2.8c2.3,0,4.101,1.8,4.101,4.1v45c0,2.3-1.801,4.1-4.101,4.1h-45c-2.3,0-4.1-1.8-4.1-4.1V7 + c0-2.3,1.8-4.1,4.1-4.1h45V2.8z"/> +<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="304.0879" y1="-376.8687" x2="304.0879" y2="-346.245" gradientTransform="matrix(1 0 0 -1 -265.5 -326)"> + <stop offset="0" style="stop-color:#0C527D"/> + <stop offset="1" style="stop-color:#FFFFFF"/> +</linearGradient> +<path fill="url(#SVGID_2_)" d="M63.5,25.4c-1.1,0-2.4,0.3-3.4,0.7c2.9,3.2,1.801,5.2,1.801,5.2s-2-4-3.2-4.8c-1.7-1.7-5-1.6-5-1.7 + c0-0.5,2.899-1,5.3,0.3c0.3-1,0.4-1.1,0.5-2.2c0.7-6-4.3-10.6-9.7-10.6c-4.6,0-8.5,2.2-9.399,6.6c1.5,0.8,2.8,2.6,2.3,5.3 + c-0.7,3.2-4.3,4.3-5.9,2.4c0.101,0,0-0.2,0.2-0.2c0.3,0.1,2.7,1,3.9-0.5c1.3-1.5,1.899-5.4-3.101-6.5c-4.7-1-9.7,5.4-9.7,10.7 + c0,0.4,0-0.4,0,0c-0.9-0.5-1.9-0.5-3-0.5c-3.7,0-6.8,3.9-6.8,7.7c0,1.5,0.5,2.101,1.4,3.2c-2.7,0.5-6.9,3.1-6,3.1 + c0.7,0,18,0.101,34.6,0c-0.8-0.399-2.7-2-3.899-3.699C42.3,36.8,45.4,32.3,45.6,32.1C46.7,31,49.4,29.2,52,29.7 + c6.5,1.2,3.9,6.6,3.8,6.8c-0.1,0.2-1.8,2.9-4.6,1.5c-2.9-1.4-0.9-3.8,0.3-3.7c1.2,0.101,1.2,0.9,1.2,0.9s0.1,0.7-0.101,0.3 + c-0.199-0.4-0.399-0.6-0.8-0.6c-0.3,0-1.3,0.5-0.8,1.699c0.4,1.101,1.6,0.7,1.9,0.7c0.3,0,2.699-0.1,2.699-3.8c0-1.9-3-2.9-4.6-2.9 + c-0.2,0-5.4,0.7-5.3,6.5c0.1,3.7,3.5,6.4,5,6.4c4.399,0,9,0,12.899,0V25.4H63.5z"/> +<line fill="none" x1="42.6" y1="56.3" x2="63.6" y2="20.5"/> +<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="304.6543" y1="-349.0195" x2="304.6543" y2="-378.2723" gradientTransform="matrix(1 0 0 -1 -265.5 -326)"> + <stop offset="0" style="stop-color:#F3F8F9"/> + <stop offset="0.2636" style="stop-color:#CDE2E7"/> + <stop offset="0.5549" style="stop-color:#9FC8D1"/> + <stop offset="1" style="stop-color:#85A8B0"/> +</linearGradient> +<path fill="url(#SVGID_3_)" d="M63.5,25.4c-1.1,0-2.4,0.3-3.4,0.7c0.2,0.3,2.9,3.3,1.801,5.2c-0.801-2.1-1.101-3-3.2-4.8 + c-2.2-2-5-1.6-5-1.7c0-0.5,2.899-1,5.3,0.3c0.3-1,0.5-2,0.5-3.1c0-5.3-4.3-9.7-9.7-9.7c-4.6,0-8.5,2.2-9.399,6.6 + c0.5,0,2.899,1.7,2.3,5.3c-0.601,3.3-4.2,4.1-5.9,2.4c0.2-0.5,2.7,1.1,4.2-0.7c1.2-1.6,1.9-5.3-2.9-6.5 + c-4.699-1-9.899,4.5-9.899,9.8c0,0.4,0,0.8,0.1,1.2c-0.9-0.5-1.9-0.7-3-0.7c-3.7,0-6.8,3-6.8,6.8c0,1.5,0.5,3,1.4,4.1 + C17.1,41,14,42.8,15,42.8c0.7,0,15.8,0.101,32.4,0C41.1,38.6,45.3,32.6,45.9,32.1c1.1-1.1,3.699-2.8,6.3-2.4 + c6.5,1.2,3.8,6.7,3.7,6.899C55.8,36.8,54.1,39.4,51.2,38c-2.9-1.5-0.9-3.8,0.3-3.7c1.2,0.101,1.2,1,1.2,1s0,0.2-0.2-0.1 + c-0.6-0.7-2.1,0.2-1.6,1.399C51.3,37.7,52.8,37.4,53,37.4c0.3,0,3.3-0.601,2.4-4.101c-0.301-1.1-0.801-1.4-1.5-1.8 + c-2.5-1.7-6-0.2-7.5,2c-0.601,0.9-1,2.3-1,3.9c0,2.899,3,4.899,5.3,5.399c4.399,0,8.7,0,12.7,0V25.4H63.5z"/> +<rect fill="none" width="64" height="64"/> +<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="289.0811" y1="-384.7373" x2="288.2475" y2="-326.2346" gradientTransform="matrix(1 0 0 -1 -265.5 -326)"> + <stop offset="0" style="stop-color:#0C527D"/> + <stop offset="1" style="stop-color:#FFFFFF"/> +</linearGradient> +<polygon fill="url(#SVGID_4_)" points="25.7,42.9 19.7,56.2 21.2,56.2 27.2,42.9 "/> +<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="287.374" y1="-345.4019" x2="287.374" y2="-398.6749" gradientTransform="matrix(1 0 0 -1 -265.5 -326)"> + <stop offset="0" style="stop-color:#000000"/> + <stop offset="0.5" style="stop-color:#A3A3A3"/> + <stop offset="1" style="stop-color:#000000"/> +</linearGradient> +<path fill="url(#SVGID_5_)" d="M18.5,60.5L18.5,60.5L18.5,60.5l15-33.6c0.2-0.3,0-0.8-0.3-0.9c-0.3-0.2-0.8,0-0.9,0.3L18.5,57.1l0,0 + L17.2,60l0,0c-0.7,1.5-2.4,2.1-3.9,1.5c-1.5-0.7-2.1-2.4-1.5-3.9l0,0l0,0c0.1-0.3,0-0.699-0.4-0.899c-0.3-0.2-0.7,0-0.9,0.3l0,0l0,0 + l0,0c0,0,0,0,0,0.1c-0.9,2.2,0.1,4.7,2.2,5.601C15,63.7,17.5,62.7,18.5,60.5L18.5,60.5L18.5,60.5z"/> +<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="257.9111" y1="-312.2236" x2="242.2144" y2="-288.1409" gradientTransform="matrix(0.9999 0.0143 0.0143 -0.9999 -220.7415 -268.9306)"> + <stop offset="0" style="stop-color:#6D110F"/> + <stop offset="1" style="stop-color:#B32024"/> +</linearGradient> +<path fill="url(#SVGID_6_)" d="M5.5,30.3c1.8,0.7,3.1,2.1,3.2,3.5c1.7-0.6,4-0.399,6.3,0.7c2,1,3.5,2.5,4.2,4.1 + c2-0.8,4.9-0.699,7.7,0.4c3.3,1.2,5.7,3.5,6.4,5.7c1.601-0.601,3.8-0.601,5.9,0.2c2.5,0.899,4.399,2.699,5,4.5 + c1.1-0.801,2.8-1,4.5-0.301c2,0.801,3.3,2.5,3.3,4l0,0C52.6,41,46.8,31.2,32.4,25.4C19.3,20.1,8.2,23.8,0.9,30.7 + C2,29.9,3.8,29.7,5.5,30.3z"/> +<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="243.5928" y1="-290.9302" x2="254.8809" y2="-304.7876" gradientTransform="matrix(0.9999 0.0143 0.0143 -0.9999 -220.7415 -268.9306)"> + <stop offset="0" style="stop-color:#6D110F"/> + <stop offset="1" style="stop-color:#B32024"/> +</linearGradient> +<path opacity="0.5" fill="url(#SVGID_7_)" enable-background="new " d="M8.7,33.8c1.7-0.6,4-0.399,6.3,0.7c2,1,3.5,2.5,4.2,4.1 + c2-0.8,4.9-0.699,7.7,0.4c3.3,1.2,5.7,3.5,6.4,5.7c1.601-0.601,3.8-0.601,5.9,0.2c2.5,0.899,4.399,2.699,5,4.5 + c1.1-0.801,0.899-18.9-11.8-24C20.6,20.6,8.6,32.4,8.7,33.8z"/> +<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="261.0293" y1="-301.6294" x2="241.5499" y2="-293.4046" gradientTransform="matrix(0.9999 0.0143 0.0143 -0.9999 -220.7415 -268.9306)"> + <stop offset="0" style="stop-color:#6D110F"/> + <stop offset="0.5275" style="stop-color:#B32024"/> + <stop offset="0.7249" style="stop-color:#981A1C"/> + <stop offset="1" style="stop-color:#6D110F"/> +</linearGradient> +<path opacity="0.5" fill="url(#SVGID_8_)" enable-background="new " d="M19.3,38.6c2-0.8,5.4-0.699,7.7,0.4 + c3.2,1.4,5.7,3.5,6.4,5.7c0.6-1.3,4.8-16.8-0.4-19.1C27.8,23.3,19.8,37.3,19.3,38.6z"/> +</svg> diff --git a/weather/images/ui_elements/button_close.png b/weather/images/ui_elements/button_close.png Binary files differnew file mode 100644 index 0000000..d1e935a --- /dev/null +++ b/weather/images/ui_elements/button_close.png diff --git a/weather/images/ui_elements/centigrades.png b/weather/images/ui_elements/centigrades.png Binary files differnew file mode 100644 index 0000000..c9298ed --- /dev/null +++ b/weather/images/ui_elements/centigrades.png diff --git a/weather/images/ui_elements/city_name_background.png b/weather/images/ui_elements/city_name_background.png Binary files differnew file mode 100644 index 0000000..8de1aab --- /dev/null +++ b/weather/images/ui_elements/city_name_background.png diff --git a/weather/images/ui_elements/division_line.png b/weather/images/ui_elements/division_line.png Binary files differnew file mode 100644 index 0000000..896c69c --- /dev/null +++ b/weather/images/ui_elements/division_line.png diff --git a/weather/images/ui_elements/icon_max.png b/weather/images/ui_elements/icon_max.png Binary files differnew file mode 100644 index 0000000..6228c74 --- /dev/null +++ b/weather/images/ui_elements/icon_max.png diff --git a/weather/images/ui_elements/icon_min.png b/weather/images/ui_elements/icon_min.png Binary files differnew file mode 100644 index 0000000..919bf67 --- /dev/null +++ b/weather/images/ui_elements/icon_min.png diff --git a/weather/images/ui_elements/list_check.png b/weather/images/ui_elements/list_check.png Binary files differnew file mode 100644 index 0000000..5abbceb --- /dev/null +++ b/weather/images/ui_elements/list_check.png diff --git a/weather/images/ui_elements/list_item_bg.png b/weather/images/ui_elements/list_item_bg.png Binary files differnew file mode 100644 index 0000000..79f4bc0 --- /dev/null +++ b/weather/images/ui_elements/list_item_bg.png diff --git a/weather/images/ui_elements/list_item_selected_bg.png b/weather/images/ui_elements/list_item_selected_bg.png Binary files differnew file mode 100644 index 0000000..24ad847 --- /dev/null +++ b/weather/images/ui_elements/list_item_selected_bg.png diff --git a/weather/images/ui_elements/list_top.png b/weather/images/ui_elements/list_top.png Binary files differnew file mode 100644 index 0000000..faa8e97 --- /dev/null +++ b/weather/images/ui_elements/list_top.png diff --git a/weather/images/ui_elements/minus_sign.png b/weather/images/ui_elements/minus_sign.png Binary files differnew file mode 100644 index 0000000..a91f055 --- /dev/null +++ b/weather/images/ui_elements/minus_sign.png diff --git a/weather/images/ui_elements/scroll.png b/weather/images/ui_elements/scroll.png Binary files differnew file mode 100644 index 0000000..376e223 --- /dev/null +++ b/weather/images/ui_elements/scroll.png diff --git a/weather/images/ui_elements/scroll_knob.png b/weather/images/ui_elements/scroll_knob.png Binary files differnew file mode 100644 index 0000000..9a6bc28 --- /dev/null +++ b/weather/images/ui_elements/scroll_knob.png diff --git a/weather/images/ui_elements/title_bar.png b/weather/images/ui_elements/title_bar.png Binary files differnew file mode 100644 index 0000000..5943884 --- /dev/null +++ b/weather/images/ui_elements/title_bar.png diff --git a/weather/images/weather_elements/bg_day_clear.png b/weather/images/weather_elements/bg_day_clear.png Binary files differnew file mode 100644 index 0000000..cee5ce4 --- /dev/null +++ b/weather/images/weather_elements/bg_day_clear.png diff --git a/weather/images/weather_elements/bg_day_heavyrain.png b/weather/images/weather_elements/bg_day_heavyrain.png Binary files differnew file mode 100644 index 0000000..1cf9122 --- /dev/null +++ b/weather/images/weather_elements/bg_day_heavyrain.png diff --git a/weather/images/weather_elements/bg_day_rain.png b/weather/images/weather_elements/bg_day_rain.png Binary files differnew file mode 100644 index 0000000..48052c5 --- /dev/null +++ b/weather/images/weather_elements/bg_day_rain.png diff --git a/weather/images/weather_elements/bg_night_clear.png b/weather/images/weather_elements/bg_night_clear.png Binary files differnew file mode 100644 index 0000000..a30a1a7 --- /dev/null +++ b/weather/images/weather_elements/bg_night_clear.png diff --git a/weather/images/weather_elements/bg_night_rain.png b/weather/images/weather_elements/bg_night_rain.png Binary files differnew file mode 100644 index 0000000..f2ae59b --- /dev/null +++ b/weather/images/weather_elements/bg_night_rain.png diff --git a/weather/images/weather_elements/cloud_1.png b/weather/images/weather_elements/cloud_1.png Binary files differnew file mode 100644 index 0000000..ed8f1c8 --- /dev/null +++ b/weather/images/weather_elements/cloud_1.png diff --git a/weather/images/weather_elements/cloud_1_line.png b/weather/images/weather_elements/cloud_1_line.png Binary files differnew file mode 100644 index 0000000..8a4b090 --- /dev/null +++ b/weather/images/weather_elements/cloud_1_line.png diff --git a/weather/images/weather_elements/cloud_2.png b/weather/images/weather_elements/cloud_2.png Binary files differnew file mode 100644 index 0000000..981bbd2 --- /dev/null +++ b/weather/images/weather_elements/cloud_2.png diff --git a/weather/images/weather_elements/cloud_2_line.png b/weather/images/weather_elements/cloud_2_line.png Binary files differnew file mode 100644 index 0000000..b9b8ca3 --- /dev/null +++ b/weather/images/weather_elements/cloud_2_line.png diff --git a/weather/images/weather_elements/cloud_3.png b/weather/images/weather_elements/cloud_3.png Binary files differnew file mode 100644 index 0000000..ea9faa2 --- /dev/null +++ b/weather/images/weather_elements/cloud_3.png diff --git a/weather/images/weather_elements/cloud_3_line.png b/weather/images/weather_elements/cloud_3_line.png Binary files differnew file mode 100644 index 0000000..0486741 --- /dev/null +++ b/weather/images/weather_elements/cloud_3_line.png diff --git a/weather/images/weather_elements/cloud_rain_1.png b/weather/images/weather_elements/cloud_rain_1.png Binary files differnew file mode 100644 index 0000000..7ae8b71 --- /dev/null +++ b/weather/images/weather_elements/cloud_rain_1.png diff --git a/weather/images/weather_elements/cloud_rain_1_line.png b/weather/images/weather_elements/cloud_rain_1_line.png Binary files differnew file mode 100644 index 0000000..204207b --- /dev/null +++ b/weather/images/weather_elements/cloud_rain_1_line.png diff --git a/weather/images/weather_elements/cloud_rain_2.png b/weather/images/weather_elements/cloud_rain_2.png Binary files differnew file mode 100644 index 0000000..b0812a3 --- /dev/null +++ b/weather/images/weather_elements/cloud_rain_2.png diff --git a/weather/images/weather_elements/cloud_rain_2_line.png b/weather/images/weather_elements/cloud_rain_2_line.png Binary files differnew file mode 100644 index 0000000..ddef2d4 --- /dev/null +++ b/weather/images/weather_elements/cloud_rain_2_line.png diff --git a/weather/images/weather_elements/cloud_rain_3.png b/weather/images/weather_elements/cloud_rain_3.png Binary files differnew file mode 100644 index 0000000..5f2a442 --- /dev/null +++ b/weather/images/weather_elements/cloud_rain_3.png diff --git a/weather/images/weather_elements/cloud_rain_3_line.png b/weather/images/weather_elements/cloud_rain_3_line.png Binary files differnew file mode 100644 index 0000000..862f631 --- /dev/null +++ b/weather/images/weather_elements/cloud_rain_3_line.png diff --git a/weather/images/weather_elements/cloud_storm_1.png b/weather/images/weather_elements/cloud_storm_1.png Binary files differnew file mode 100644 index 0000000..147656f --- /dev/null +++ b/weather/images/weather_elements/cloud_storm_1.png diff --git a/weather/images/weather_elements/cloud_storm_1_line.png b/weather/images/weather_elements/cloud_storm_1_line.png Binary files differnew file mode 100644 index 0000000..013a082 --- /dev/null +++ b/weather/images/weather_elements/cloud_storm_1_line.png diff --git a/weather/images/weather_elements/cloud_storm_2.png b/weather/images/weather_elements/cloud_storm_2.png Binary files differnew file mode 100644 index 0000000..2f02fa7 --- /dev/null +++ b/weather/images/weather_elements/cloud_storm_2.png diff --git a/weather/images/weather_elements/cloud_storm_2_line.png b/weather/images/weather_elements/cloud_storm_2_line.png Binary files differnew file mode 100644 index 0000000..51b38b1 --- /dev/null +++ b/weather/images/weather_elements/cloud_storm_2_line.png diff --git a/weather/images/weather_elements/cloud_storm_3.png b/weather/images/weather_elements/cloud_storm_3.png Binary files differnew file mode 100644 index 0000000..3bc4f02 --- /dev/null +++ b/weather/images/weather_elements/cloud_storm_3.png diff --git a/weather/images/weather_elements/cloud_storm_3_line.png b/weather/images/weather_elements/cloud_storm_3_line.png Binary files differnew file mode 100644 index 0000000..ad52b91 --- /dev/null +++ b/weather/images/weather_elements/cloud_storm_3_line.png diff --git a/weather/images/weather_elements/cloud_tstorm_1.png b/weather/images/weather_elements/cloud_tstorm_1.png Binary files differnew file mode 100644 index 0000000..4de4bc8 --- /dev/null +++ b/weather/images/weather_elements/cloud_tstorm_1.png diff --git a/weather/images/weather_elements/cloud_tstorm_1_line.png b/weather/images/weather_elements/cloud_tstorm_1_line.png Binary files differnew file mode 100644 index 0000000..013a082 --- /dev/null +++ b/weather/images/weather_elements/cloud_tstorm_1_line.png diff --git a/weather/images/weather_elements/cloud_tstorm_2.png b/weather/images/weather_elements/cloud_tstorm_2.png Binary files differnew file mode 100644 index 0000000..e3e60c7 --- /dev/null +++ b/weather/images/weather_elements/cloud_tstorm_2.png diff --git a/weather/images/weather_elements/cloud_tstorm_2_line.png b/weather/images/weather_elements/cloud_tstorm_2_line.png Binary files differnew file mode 100644 index 0000000..51b38b1 --- /dev/null +++ b/weather/images/weather_elements/cloud_tstorm_2_line.png diff --git a/weather/images/weather_elements/cold_sun.png b/weather/images/weather_elements/cold_sun.png Binary files differnew file mode 100644 index 0000000..1493215 --- /dev/null +++ b/weather/images/weather_elements/cold_sun.png diff --git a/weather/images/weather_elements/cold_sun_line.png b/weather/images/weather_elements/cold_sun_line.png Binary files differnew file mode 100644 index 0000000..f51062b --- /dev/null +++ b/weather/images/weather_elements/cold_sun_line.png diff --git a/weather/images/weather_elements/fog.png b/weather/images/weather_elements/fog.png Binary files differnew file mode 100644 index 0000000..1f95acf --- /dev/null +++ b/weather/images/weather_elements/fog.png diff --git a/weather/images/weather_elements/haze.png b/weather/images/weather_elements/haze.png Binary files differnew file mode 100644 index 0000000..2f53bd0 --- /dev/null +++ b/weather/images/weather_elements/haze.png diff --git a/weather/images/weather_elements/moon.png b/weather/images/weather_elements/moon.png Binary files differnew file mode 100644 index 0000000..0a8037d --- /dev/null +++ b/weather/images/weather_elements/moon.png diff --git a/weather/images/weather_elements/moon_line.png b/weather/images/weather_elements/moon_line.png Binary files differnew file mode 100644 index 0000000..449cb4a --- /dev/null +++ b/weather/images/weather_elements/moon_line.png diff --git a/weather/images/weather_elements/rain_01.png b/weather/images/weather_elements/rain_01.png Binary files differnew file mode 100644 index 0000000..c35f47a --- /dev/null +++ b/weather/images/weather_elements/rain_01.png diff --git a/weather/images/weather_elements/rain_02.png b/weather/images/weather_elements/rain_02.png Binary files differnew file mode 100644 index 0000000..cbc9a74 --- /dev/null +++ b/weather/images/weather_elements/rain_02.png diff --git a/weather/images/weather_elements/rain_03.png b/weather/images/weather_elements/rain_03.png Binary files differnew file mode 100644 index 0000000..9d36a7c --- /dev/null +++ b/weather/images/weather_elements/rain_03.png diff --git a/weather/images/weather_elements/snow_flake.png b/weather/images/weather_elements/snow_flake.png Binary files differnew file mode 100644 index 0000000..39c5751 --- /dev/null +++ b/weather/images/weather_elements/snow_flake.png diff --git a/weather/images/weather_elements/snow_flake_01.png b/weather/images/weather_elements/snow_flake_01.png Binary files differnew file mode 100644 index 0000000..39c5751 --- /dev/null +++ b/weather/images/weather_elements/snow_flake_01.png diff --git a/weather/images/weather_elements/snow_flake_02.png b/weather/images/weather_elements/snow_flake_02.png Binary files differnew file mode 100644 index 0000000..3aaeb24 --- /dev/null +++ b/weather/images/weather_elements/snow_flake_02.png diff --git a/weather/images/weather_elements/snow_flake_03.png b/weather/images/weather_elements/snow_flake_03.png Binary files differnew file mode 100644 index 0000000..a84c736 --- /dev/null +++ b/weather/images/weather_elements/snow_flake_03.png diff --git a/weather/images/weather_elements/snow_flake_04.png b/weather/images/weather_elements/snow_flake_04.png Binary files differnew file mode 100644 index 0000000..007d921 --- /dev/null +++ b/weather/images/weather_elements/snow_flake_04.png diff --git a/weather/images/weather_elements/snow_flake_05.png b/weather/images/weather_elements/snow_flake_05.png Binary files differnew file mode 100644 index 0000000..c833da1 --- /dev/null +++ b/weather/images/weather_elements/snow_flake_05.png diff --git a/weather/images/weather_elements/snow_flake_06.png b/weather/images/weather_elements/snow_flake_06.png Binary files differnew file mode 100644 index 0000000..2db4a02 --- /dev/null +++ b/weather/images/weather_elements/snow_flake_06.png diff --git a/weather/images/weather_elements/snow_flake_07.png b/weather/images/weather_elements/snow_flake_07.png Binary files differnew file mode 100644 index 0000000..e1a3bed --- /dev/null +++ b/weather/images/weather_elements/snow_flake_07.png diff --git a/weather/images/weather_elements/snow_flake_08.png b/weather/images/weather_elements/snow_flake_08.png Binary files differnew file mode 100644 index 0000000..5a6ac67 --- /dev/null +++ b/weather/images/weather_elements/snow_flake_08.png diff --git a/weather/images/weather_elements/snow_flake_09.png b/weather/images/weather_elements/snow_flake_09.png Binary files differnew file mode 100644 index 0000000..bbee2d9 --- /dev/null +++ b/weather/images/weather_elements/snow_flake_09.png diff --git a/weather/images/weather_elements/star_01.png b/weather/images/weather_elements/star_01.png Binary files differnew file mode 100644 index 0000000..9648e70 --- /dev/null +++ b/weather/images/weather_elements/star_01.png diff --git a/weather/images/weather_elements/star_02.png b/weather/images/weather_elements/star_02.png Binary files differnew file mode 100644 index 0000000..01e920f --- /dev/null +++ b/weather/images/weather_elements/star_02.png diff --git a/weather/images/weather_elements/star_03.png b/weather/images/weather_elements/star_03.png Binary files differnew file mode 100644 index 0000000..80816b0 --- /dev/null +++ b/weather/images/weather_elements/star_03.png diff --git a/weather/images/weather_elements/sun.png b/weather/images/weather_elements/sun.png Binary files differnew file mode 100644 index 0000000..304cae9 --- /dev/null +++ b/weather/images/weather_elements/sun.png diff --git a/weather/images/weather_elements/sun_line.png b/weather/images/weather_elements/sun_line.png Binary files differnew file mode 100644 index 0000000..f963c27 --- /dev/null +++ b/weather/images/weather_elements/sun_line.png diff --git a/weather/images/weather_elements/thunder.png b/weather/images/weather_elements/thunder.png Binary files differnew file mode 100644 index 0000000..d07b36b --- /dev/null +++ b/weather/images/weather_elements/thunder.png diff --git a/weather/linux.ini b/weather/linux.ini new file mode 100644 index 0000000..e9a2ea6 --- /dev/null +++ b/weather/linux.ini @@ -0,0 +1,20 @@ +[General] +windowSize = @Size(480 864) +list_cities_size = @Size(480 800) +increased_close_button = 15 + +[Timezones] +Vancouver = -8 +San Francisco = -8 +Rio de Janeiro = -3 +London = 0 +Beijing = 8 +Tokyo = 9 +Cairo = 2 + +[Selected Cities] +New York = -5 +Oslo = 1 +Cape Town = 2 +Moscow = 3 +Brisbane = 10 diff --git a/weather/main.cpp b/weather/main.cpp new file mode 100644 index 0000000..cb7bfda --- /dev/null +++ b/weather/main.cpp @@ -0,0 +1,75 @@ +#include <QApplication> +#include <QGraphicsScene> +#include <QGraphicsView> +#include <QPixmapCache> +#include <QSettings> +#include <QDebug> + +#include "mainview.h" +#include "settings.h" +#include "forecaststars.h" +#include "forecastsnow.h" +#include "forecastrain.h" + +#include "forecasthungitem.h" +#include "forecastview.h" +#include "citycarroussel.h" + +// MainHelperHack + +class MyCityForecastData : public CityForecastData +{ +public: + MyCityForecastData(Forecast::ForecastType forecast, bool night) + : m_forecast(forecast) + , m_night(night) {} + Forecast::ForecastType forecast() const { return m_forecast; } + bool night() const { return m_night; } +private: + Forecast::ForecastType m_forecast; + bool m_night; +}; + +void MainHelperHack::exec() +{ +} + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + QCoreApplication::setOrganizationName("openBossa"); + QCoreApplication::setOrganizationDomain("openbossa.org"); + QCoreApplication::setApplicationName("weather"); + + QPixmapCache::setCacheLimit(0); + QSize windowSize(Settings::windowSize()); + QGraphicsScene scene; + scene.setSceneRect(0, 0, windowSize.width(), windowSize.height()); + + MainView mainView(&scene); +// mainView.setFixedSize(windowSize); + mainView.setGeometry(QRect(QPoint(0, 0), windowSize)); + scene.setBackgroundBrush(Qt::black); + +#ifdef Q_OS_SYMBIAN + mainView.showFullScreen(); + Settings::fixedPortraitOrientation(); +#else + mainView.show(); +#endif + + CityCarroussel carroussel; + + for (int i = Forecast::MostlyCloudy; i < Forecast::UnknownForecast; ++i) { + carroussel.add(new MyCityForecastData(Forecast::ForecastType(i), false)); + carroussel.add(new MyCityForecastData(Forecast::ForecastType(i), true)); + } + + carroussel.add(new MyCityForecastData(Forecast::Rain, false)); + carroussel.add(new MyCityForecastData(Forecast::Snow, true)); + + carroussel.setPos(0.0, 0.0); + scene.addItem(&carroussel); + + return app.exec(); +} diff --git a/weather/mainview.cpp b/weather/mainview.cpp new file mode 100644 index 0000000..0851865 --- /dev/null +++ b/weather/mainview.cpp @@ -0,0 +1,19 @@ +#include "mainview.h" + +MainView::MainView(QGraphicsScene* scene) + : QGraphicsView(scene) +{ + setFrameShape(QFrame::NoFrame); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); + setWindowTitle("Weather"); +} + +void MainView::keyPressEvent(QKeyEvent* event) +{ + if (event->key() == Qt::Key_Left) + emit moveLeft(); + if (event->key() == Qt::Key_Right) + emit moveRight(); +} diff --git a/weather/mainview.h b/weather/mainview.h new file mode 100644 index 0000000..fc766fa --- /dev/null +++ b/weather/mainview.h @@ -0,0 +1,31 @@ +#ifndef MAINVIEW_H +#define MAINVIEW_H + +#include <QGraphicsView> +#include <QKeyEvent> +#include <QGraphicsScene> + +class MainHelperHack : public QObject +{ + Q_OBJECT +public: +public slots: + void exec(); +private: +}; + +class MainView: public QGraphicsView +{ + Q_OBJECT + +public: + MainView(QGraphicsScene* scene); + void keyPressEvent(QKeyEvent* event); + +signals: + void moveLeft(); + void moveRight(); +}; + +#endif // MAINVIEW_H + diff --git a/weather/resources.qrc b/weather/resources.qrc new file mode 100644 index 0000000..f449dbd --- /dev/null +++ b/weather/resources.qrc @@ -0,0 +1,70 @@ +<RCC> + <qresource prefix="/"> + <file>images/ui_elements/centigrades.png</file> + <file>images/ui_elements/division_line.png</file> + <file>images/ui_elements/icon_min.png</file> + <file>images/ui_elements/icon_max.png</file> + <file>images/ui_elements/minus_sign.png</file> + <file>images/ui_elements/title_bar.png</file> + <file>images/ui_elements/button_close.png</file> + <file>images/ui_elements/city_name_background.png</file> + <file>images/ui_elements/list_check.png</file> + <file>images/ui_elements/list_item_bg.png</file> + <file>images/ui_elements/list_item_selected_bg.png</file> + <file>images/ui_elements/list_top.png</file> + <file>images/ui_elements/scroll.png</file> + <file>images/ui_elements/scroll_knob.png</file> + <file>images/weather_elements/bg_day_clear.png</file> + <file>images/weather_elements/bg_day_heavyrain.png</file> + <file>images/weather_elements/bg_day_rain.png</file> + <file>images/weather_elements/bg_night_clear.png</file> + <file>images/weather_elements/bg_night_rain.png</file> + <file>images/weather_elements/cloud_1_line.png</file> + <file>images/weather_elements/cloud_1.png</file> + <file>images/weather_elements/cloud_2_line.png</file> + <file>images/weather_elements/cloud_2.png</file> + <file>images/weather_elements/cloud_3_line.png</file> + <file>images/weather_elements/cloud_3.png</file> + <file>images/weather_elements/cloud_rain_1_line.png</file> + <file>images/weather_elements/cloud_rain_1.png</file> + <file>images/weather_elements/cloud_rain_2_line.png</file> + <file>images/weather_elements/cloud_rain_2.png</file> + <file>images/weather_elements/cloud_rain_3_line.png</file> + <file>images/weather_elements/cloud_rain_3.png</file> + <file>images/weather_elements/cloud_storm_1_line.png</file> + <file>images/weather_elements/cloud_storm_1.png</file> + <file>images/weather_elements/cloud_storm_2_line.png</file> + <file>images/weather_elements/cloud_storm_2.png</file> + <file>images/weather_elements/cloud_storm_3_line.png</file> + <file>images/weather_elements/cloud_storm_3.png</file> + <file>images/weather_elements/cloud_tstorm_1_line.png</file> + <file>images/weather_elements/cloud_tstorm_1.png</file> + <file>images/weather_elements/cloud_tstorm_2_line.png</file> + <file>images/weather_elements/cloud_tstorm_2.png</file> + <file>images/weather_elements/cold_sun_line.png</file> + <file>images/weather_elements/cold_sun.png</file> + <file>images/weather_elements/fog.png</file> + <file>images/weather_elements/haze.png</file> + <file>images/weather_elements/moon_line.png</file> + <file>images/weather_elements/moon.png</file> + <file>images/weather_elements/rain_01.png</file> + <file>images/weather_elements/rain_02.png</file> + <file>images/weather_elements/rain_03.png</file> + <file>images/weather_elements/sun_line.png</file> + <file>images/weather_elements/sun.png</file> + <file>images/weather_elements/thunder.png</file> + <file>images/weather_elements/star_01.png</file> + <file>images/weather_elements/star_02.png</file> + <file>images/weather_elements/star_03.png</file> + <file>images/weather_elements/snow_flake_01.png</file> + <file>images/weather_elements/snow_flake_02.png</file> + <file>images/weather_elements/snow_flake_03.png</file> + <file>images/weather_elements/snow_flake_04.png</file> + <file>images/weather_elements/snow_flake_05.png</file> + <file>images/weather_elements/snow_flake_06.png</file> + <file>images/weather_elements/snow_flake_07.png</file> + <file>images/weather_elements/snow_flake_08.png</file> + <file>images/weather_elements/snow_flake_09.png</file> + <file>images/weather_elements/snow_flake.png</file> + </qresource> +</RCC> diff --git a/weather/settings.cpp b/weather/settings.cpp new file mode 100644 index 0000000..6b5ddde --- /dev/null +++ b/weather/settings.cpp @@ -0,0 +1,78 @@ +#include "settings.h" +#include <QTimer> +#include <QDebug> + +#ifdef Q_OS_SYMBIAN +#include <eikenv.h> +#include <coemain.h> +#include <aknappui.h> + +#define SETTINGS_FILE "e://resources/apps/symbian.ini" +#else +#define SETTINGS_FILE "linux.ini" +#endif + +Settings::Settings() + : m_settings(SETTINGS_FILE, QSettings::IniFormat) +{ +} + +Settings *Settings::instance() +{ + static Settings * const result = new Settings(); + return result; +} + +QSize Settings::windowSize() +{ + static const QSize result(instance()->m_settings.value("windowSize").toSize()); + return result; +} + +bool Settings::scaledImages() +{ + QSize size(windowSize()); + return size.width() != 480 || size.height() != 864; +} + +QPixmap Settings::getScaledPic(const QString &name) +{ + Settings *obj = instance(); + if (obj->m_scaledPixmaps.contains(name)) + return obj->m_scaledPixmaps[name]; + + QPixmap pic(":images/weather_elements/" + name + ".png"); + if (!pic.isNull() || scaledImages()) { + + int width = pic.width() * widthFactor(); + int height = pic.height() * heightFactor(); + +// width = !width ? pic.width() : width; +// height = !height ? pic.height() : height; + + if (width && height) + pic = pic.scaled(QSize(width, height), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + } + if (pic.isNull()) + qWarning() << "ERROR: unable to open pixmap " << name; + else + obj->m_scaledPixmaps[name] = pic; + return pic; +} + +void Settings::configPortrait() +{ +#ifdef Q_OS_SYMBIAN + CAknAppUi* appUi = dynamic_cast<CAknAppUi*>(CEikonEnv::Static()->AppUi()); + if (appUi) { + appUi->SetOrientationL(CAknAppUi::EAppUiOrientationPortrait); + } +#endif +} + +void Settings::fixedPortraitOrientation() +{ +#ifdef Q_OS_SYMBIAN + QTimer::singleShot(1, instance(), SLOT(configPortrait())); +#endif +} diff --git a/weather/settings.h b/weather/settings.h new file mode 100644 index 0000000..1cbe8a6 --- /dev/null +++ b/weather/settings.h @@ -0,0 +1,44 @@ +#ifndef SETTINGS_H +#define SETTINGS_H + +#include <QObject> +#include <QSettings> +#include <QSize> +#include <QPixmap> + +class Settings : public QObject +{ + Q_OBJECT +public: + Settings(); + + static QString elementPath(const QString & element) + { return ":images/weather_elements/" + element; } + + static void fixedPortraitOrientation(); + + static QSize windowSize(); + static bool scaledImages(); + + static qreal referenceWidth() { return 480.0; } + static qreal referenceHeight() { return 864.0; } + + static qreal widthFactor() { return qreal(windowSize().width()) / referenceWidth(); } + static qreal heightFactor() { return qreal(windowSize().height()) / referenceHeight(); } + + static qreal scaleWidth(qreal width) { return width * widthFactor(); } + static qreal scaleHeight(qreal height) { return height * heightFactor(); } + + static QPixmap getScaledPic(const QString &name); + +private slots: + void configPortrait(); + +private: + QSettings m_settings; + QHash<QString, QPixmap> m_scaledPixmaps; + static Settings *instance(); + +}; + +#endif // SETTINGS_H diff --git a/weather/symbian.ini b/weather/symbian.ini new file mode 100644 index 0000000..6c37c72 --- /dev/null +++ b/weather/symbian.ini @@ -0,0 +1,20 @@ +[General] +windowSize = @Size(360 640) +list_cities_size = @Size(480 800) +increased_close_button = 15 + +[Timezones] +Vancouver = -8 +San Francisco = -8 +Rio de Janeiro = -3 +London = 0 +Beijing = 8 +Tokyo = 9 +Cairo = 2 + +[Selected Cities] +New York = -5 +Oslo = 1 +Cape Town = 2 +Moscow = 3 +Brisbane = 10 diff --git a/weather/symbian_3.2.ini b/weather/symbian_3.2.ini new file mode 100644 index 0000000..b022c8f --- /dev/null +++ b/weather/symbian_3.2.ini @@ -0,0 +1,81 @@ +[General] +windowSize = @Size(240 320) +title_bar_size = @Size(240 24) +city_bar_size = @Size(240 64) +close_button_size = @Size(10 10) +centigrades_size = @Size(35 48) +divisionLine_size = @Size(135 1) +hi_size = @Size(5 7) +low_size = @Size(5 7) +bg_size = @Size(317 320) +sun_size = @Size(149 149) +cold_sun_size = @Size(121 121) +moon_size = @Size(98 96) +sun_line_size = @Size(1 122) +cold_sun_line_size = @Size(1 122) +moon_line_size = @Size(1 122) +cloud_1_size = @Size(180 76) +cloud_2_size = @Size(148 66) +cloud_3_size = @Size(114 54) +cloud_rain_1_size = @Size(180 76) +cloud_rain_2_size = @Size(148 66) +cloud_rain_3_size = @Size(114 54) +cloud_storm_1_size = @Size(180 76) +cloud_storm_2_size = @Size(148 66) +cloud_storm_3_size = @Size(114 54) +cloud_tstorm_1_size = @Size(180 102) +cloud_tstorm_2_size = @Size(148 80) +cloud_1_line_size = @Size(1 187) +cloud_2_line_size = @Size(1 187) +cloud_3_line_size = @Size(1 187) +cloud_rain_1_line_size = @Size(1 187) +cloud_rain_2_line_size = @Size(1 187) +cloud_rain_3_line_size = @Size(1 187) +cloud_storm_1_line_size = @Size(1 187) +cloud_storm_2_line_size = @Size(1 187) +cloud_storm_3_line_size = @Size(1 187) +cloud_tstorm_1_line_size = @Size(1 187) +cloud_tstorm_2_line_size = @Size(1 187) +sleet_size = @Size(180 180) +sleet_rain_size = @Size(180 180) +rain_01_size = @Size(290 175) +rain_02_size = @Size(290 175) +rain_03_size = @Size(290 175) +star_01_size = @Size(30 30) +star_02_size = @Size(28 28) +star_03_size = @Size(25 25) +snow_flake_01_size = @Size(12 12) +snow_flake_02_size = @Size(15 15) +snow_flake_03_size = @Size(17 17) +snow_flake_04_size = @Size(12 12) +snow_flake_05_size = @Size(15 15) +snow_flake_06_size = @Size(17 17) +snow_flake_07_size = @Size(15 15) +snow_flake_08_size = @Size(17 17) +snow_flake_09_size = @Size(9 9) +flurries_size = @Size(240 240) +fog_size = @Size(317 324) +haze_size = @Size(317 324) +snow_size = @Size(240 240) +list_top_size = @Size(240 8) +list_item_bg_size = @Size(240 30) +list_cities_size = @Size(240 300) +list_checkbox_size = @Size(14 11) +scroll_size = @Size(4 275) +scroll_knob_size = @Size(5 30) + + +[Timezones] +Vancouver = -8 +San Francisco = -8 +Rio de Janeiro = -3 +London = 0 +Beijing = 8 +Tokyo = 9 + +[Selected Cities] +New York = -5 +Oslo = 1 +Cape Town = 2 +Moscow = 3 +Brisbane = 10 diff --git a/weather/weather.pro b/weather/weather.pro new file mode 100644 index 0000000..fcc1eee --- /dev/null +++ b/weather/weather.pro @@ -0,0 +1,49 @@ +TEMPLATE = app +TARGET = weather +QT += network +target.path = $$PREFIX/bin +INSTALLS += target +RESOURCES += resources.qrc +QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.5 +symbian { + LIBS += -lesock \ + -lconnmon \ + -lcone \ + -lavkon + addFiles.sources = symbian.ini + addFiles.path = e:\resources\apps + DEPLOYMENT += addFiles + ICON = images/icon.svg + OBJECTS_DIR = tmp + MOC_DIR = tmp + TARGET.CAPABILITY = NetworkServices + TARGET.EPOCHEAPSIZE = 0x20000 \ + 0x2000000 + TARGET.UID3 = 0xe1234567 +} +unix { + OBJECTS_DIR = tmp + MOC_DIR = tmp +} +HEADERS += mainview.h \ + settings.h \ + forecastview.h \ + forecasthungitem.h \ + forecaststars.h \ + forecastsnow.h \ + forecastrain.h \ + forecast.h \ + carroussel.h \ + citycarroussel.h \ + gesturebox_p.h \ + gesturebox.h +SOURCES += mainview.cpp \ + main.cpp \ + settings.cpp \ + forecastview.cpp \ + forecasthungitem.cpp \ + forecaststars.cpp \ + forecastsnow.cpp \ + forecastrain.cpp \ + citycarroussel.cpp \ + gesturebox.cpp |